"""
TacticalProcessor - Tier 2: TACTICAL Features (44 columns)

Calculates tactical gameplay features from fact_match_players and fact_round_events:
- Opening Impact (8 columns): first kills/deaths, entry duels
- Multi-Kill Performance (6 columns): 2k, 3k, 4k, 5k, ace
- Clutch Performance (10 columns): 1v1, 1v2, 1v3+ situations
- Utility Mastery (12 columns): nade damage, flash efficiency, smoke timing
- Economy Efficiency (8 columns): damage/$, eco/force/full round performance
"""

import sqlite3
from typing import Dict, Any
from .base_processor import BaseFeatureProcessor, SafeAggregator


class TacticalProcessor(BaseFeatureProcessor):
    """Tier 2 TACTICAL processor - Multi-table JOINs and conditional aggregations"""
    
    MIN_MATCHES_REQUIRED = 5  # Need reasonable sample for tactical analysis
    
    @staticmethod
    def calculate(steam_id: str, conn_l2: sqlite3.Connection) -> Dict[str, Any]:
        """
        Calculate all Tier 2 TACTICAL features (44 columns)
        
        Returns dict with keys starting with 'tac_'
        """
        features = {}
        
        # Check minimum matches
        if not BaseFeatureProcessor.check_min_matches(steam_id, conn_l2, 
                                                       TacticalProcessor.MIN_MATCHES_REQUIRED):
            return _get_default_tactical_features()
        
        # Calculate each tactical dimension
        features.update(TacticalProcessor._calculate_opening_impact(steam_id, conn_l2))
        features.update(TacticalProcessor._calculate_multikill(steam_id, conn_l2))
        features.update(TacticalProcessor._calculate_clutch(steam_id, conn_l2))
        features.update(TacticalProcessor._calculate_utility(steam_id, conn_l2))
        features.update(TacticalProcessor._calculate_economy(steam_id, conn_l2))
        
        return features
    
    @staticmethod
    def _calculate_opening_impact(steam_id: str, conn_l2: sqlite3.Connection) -> Dict[str, Any]:
        """
        Calculate Opening Impact (8 columns)
        
        Columns:
        - tac_avg_fk, tac_avg_fd
        - tac_fk_rate, tac_fd_rate
        - tac_fk_success_rate (team win rate when player gets FK)
        - tac_entry_kill_rate, tac_entry_death_rate
        - tac_opening_duel_winrate
        """
        cursor = conn_l2.cursor()
        
        # FK/FD from fact_match_players
        cursor.execute("""
            SELECT 
                AVG(entry_kills) as avg_fk,
                AVG(entry_deaths) as avg_fd,
                SUM(entry_kills) as total_fk,
                SUM(entry_deaths) as total_fd,
                COUNT(*) as total_matches
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        
        row = cursor.fetchone()
        avg_fk = row[0] if row[0] else 0.0
        avg_fd = row[1] if row[1] else 0.0
        total_fk = row[2] if row[2] else 0
        total_fd = row[3] if row[3] else 0
        total_matches = row[4] if row[4] else 1
        
        opening_duels = total_fk + total_fd
        fk_rate = SafeAggregator.safe_divide(total_fk, opening_duels)
        fd_rate = SafeAggregator.safe_divide(total_fd, opening_duels)
        opening_duel_winrate = SafeAggregator.safe_divide(total_fk, opening_duels)
        
        # FK success rate: team win rate when player gets FK
        cursor.execute("""
            SELECT 
                COUNT(*) as fk_matches,
                SUM(CASE WHEN is_win = 1 THEN 1 ELSE 0 END) as fk_wins
            FROM fact_match_players
            WHERE steam_id_64 = ?
            AND entry_kills > 0
        """, (steam_id,))
        
        fk_row = cursor.fetchone()
        fk_matches = fk_row[0] if fk_row[0] else 0
        fk_wins = fk_row[1] if fk_row[1] else 0
        fk_success_rate = SafeAggregator.safe_divide(fk_wins, fk_matches)
        
        # Entry kill/death rates (per T round for entry kills, total for entry deaths)
        cursor.execute("""
            SELECT COALESCE(SUM(round_total), 0)
            FROM fact_match_players_t
            WHERE steam_id_64 = ?
        """, (steam_id,))
        t_rounds = cursor.fetchone()[0] or 1
        
        cursor.execute("""
            SELECT COALESCE(SUM(round_total), 0)
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        total_rounds = cursor.fetchone()[0] or 1
        
        entry_kill_rate = SafeAggregator.safe_divide(total_fk, t_rounds)
        entry_death_rate = SafeAggregator.safe_divide(total_fd, total_rounds)
        
        return {
            'tac_avg_fk': round(avg_fk, 2),
            'tac_avg_fd': round(avg_fd, 2),
            'tac_fk_rate': round(fk_rate, 3),
            'tac_fd_rate': round(fd_rate, 3),
            'tac_fk_success_rate': round(fk_success_rate, 3),
            'tac_entry_kill_rate': round(entry_kill_rate, 3),
            'tac_entry_death_rate': round(entry_death_rate, 3),
            'tac_opening_duel_winrate': round(opening_duel_winrate, 3),
        }
    
    @staticmethod
    def _calculate_multikill(steam_id: str, conn_l2: sqlite3.Connection) -> Dict[str, Any]:
        """
        Calculate Multi-Kill Performance (6 columns)
        
        Columns:
        - tac_avg_2k, tac_avg_3k, tac_avg_4k, tac_avg_5k
        - tac_multikill_rate
        - tac_ace_count
        """
        cursor = conn_l2.cursor()
        
        cursor.execute("""
            SELECT 
                AVG(kill_2) as avg_2k,
                AVG(kill_3) as avg_3k,
                AVG(kill_4) as avg_4k,
                AVG(kill_5) as avg_5k,
                SUM(kill_2) as total_2k,
                SUM(kill_3) as total_3k,
                SUM(kill_4) as total_4k,
                SUM(kill_5) as total_5k,
                SUM(round_total) as total_rounds
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        
        row = cursor.fetchone()
        avg_2k = row[0] if row[0] else 0.0
        avg_3k = row[1] if row[1] else 0.0
        avg_4k = row[2] if row[2] else 0.0
        avg_5k = row[3] if row[3] else 0.0
        total_2k = row[4] if row[4] else 0
        total_3k = row[5] if row[5] else 0
        total_4k = row[6] if row[6] else 0
        total_5k = row[7] if row[7] else 0
        total_rounds = row[8] if row[8] else 1
        
        total_multikills = total_2k + total_3k + total_4k + total_5k
        multikill_rate = SafeAggregator.safe_divide(total_multikills, total_rounds)
        
        return {
            'tac_avg_2k': round(avg_2k, 2),
            'tac_avg_3k': round(avg_3k, 2),
            'tac_avg_4k': round(avg_4k, 2),
            'tac_avg_5k': round(avg_5k, 2),
            'tac_multikill_rate': round(multikill_rate, 3),
            'tac_ace_count': total_5k,
        }
    
    @staticmethod
    def _calculate_clutch(steam_id: str, conn_l2: sqlite3.Connection) -> Dict[str, Any]:
        """
        Calculate Clutch Performance (10 columns)
        
        Columns:
        - tac_clutch_1v1_attempts, tac_clutch_1v1_wins, tac_clutch_1v1_rate
        - tac_clutch_1v2_attempts, tac_clutch_1v2_wins, tac_clutch_1v2_rate
        - tac_clutch_1v3_plus_attempts, tac_clutch_1v3_plus_wins, tac_clutch_1v3_plus_rate
        - tac_clutch_impact_score
        
        Logic:
        - Wins: Aggregated directly from fact_match_players (trusting upstream data).
        - Attempts: Calculated by replaying rounds with 'Active Player' filtering to remove ghosts.
        """
        cursor = conn_l2.cursor()
        
        # Step 1: Get Wins from fact_match_players
        cursor.execute("""
            SELECT 
                SUM(clutch_1v1) as c1,
                SUM(clutch_1v2) as c2,
                SUM(clutch_1v3) as c3,
                SUM(clutch_1v4) as c4,
                SUM(clutch_1v5) as c5
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        
        wins_row = cursor.fetchone()
        clutch_1v1_wins = wins_row[0] if wins_row and wins_row[0] else 0
        clutch_1v2_wins = wins_row[1] if wins_row and wins_row[1] else 0
        clutch_1v3_wins = wins_row[2] if wins_row and wins_row[2] else 0
        clutch_1v4_wins = wins_row[3] if wins_row and wins_row[3] else 0
        clutch_1v5_wins = wins_row[4] if wins_row and wins_row[4] else 0
        
        # Group 1v3+ wins
        clutch_1v3_plus_wins = clutch_1v3_wins + clutch_1v4_wins + clutch_1v5_wins

        # Step 2: Calculate Attempts
        cursor.execute("SELECT DISTINCT match_id FROM fact_match_players WHERE steam_id_64 = ?", (steam_id,))
        match_ids = [row[0] for row in cursor.fetchall()]
        
        clutch_1v1_attempts = 0
        clutch_1v2_attempts = 0
        clutch_1v3_plus_attempts = 0
        
        for match_id in match_ids:
            # Get Roster
            cursor.execute("SELECT steam_id_64, team_id FROM fact_match_players WHERE match_id = ?", (match_id,))
            roster = cursor.fetchall()
            
            my_team_id = None
            for pid, tid in roster:
                if str(pid) == str(steam_id):
                    my_team_id = tid
                    break
            
            if my_team_id is None:
                continue
                
            all_teammates = {str(pid) for pid, tid in roster if tid == my_team_id}
            all_enemies = {str(pid) for pid, tid in roster if tid != my_team_id}
            
            # Get Events for this match
            cursor.execute("""
                SELECT round_num, event_type, attacker_steam_id, victim_steam_id, event_time
                FROM fact_round_events 
                WHERE match_id = ?
                ORDER BY round_num, event_time
            """, (match_id,))
            all_events = cursor.fetchall()
            
            # Group events by round
            from collections import defaultdict
            events_by_round = defaultdict(list)
            active_players_by_round = defaultdict(set)
            
            for r_num, e_type, attacker, victim, e_time in all_events:
                events_by_round[r_num].append((e_type, attacker, victim))
                if attacker: active_players_by_round[r_num].add(str(attacker))
                if victim: active_players_by_round[r_num].add(str(victim))
            
            # Iterate rounds
            for r_num, round_events in events_by_round.items():
                active_players = active_players_by_round[r_num]
                
                # If player not active, skip (probably camping or AFK or not spawned)
                if str(steam_id) not in active_players:
                    continue
                
                # Filter roster to active players only (removes ghosts)
                alive_teammates = all_teammates.intersection(active_players)
                alive_enemies = all_enemies.intersection(active_players)
                
                # Safety: ensure player is in alive_teammates
                alive_teammates.add(str(steam_id))
                
                clutch_detected = False
                
                for e_type, attacker, victim in round_events:
                    if e_type == 'kill':
                        vic_str = str(victim)
                        if vic_str in alive_teammates:
                            alive_teammates.discard(vic_str)
                        elif vic_str in alive_enemies:
                            alive_enemies.discard(vic_str)
                            
                        # Check clutch condition
                        if not clutch_detected:
                            # Teammates dead (len==1 means only me), Enemies alive
                            if len(alive_teammates) == 1 and str(steam_id) in alive_teammates:
                                enemies_cnt = len(alive_enemies)
                                if enemies_cnt > 0:
                                    clutch_detected = True
                                    if enemies_cnt == 1:
                                        clutch_1v1_attempts += 1
                                    elif enemies_cnt == 2:
                                        clutch_1v2_attempts += 1
                                    elif enemies_cnt >= 3:
                                        clutch_1v3_plus_attempts += 1
        
        # Calculate win rates
        rate_1v1 = SafeAggregator.safe_divide(clutch_1v1_wins, clutch_1v1_attempts)
        rate_1v2 = SafeAggregator.safe_divide(clutch_1v2_wins, clutch_1v2_attempts)
        rate_1v3_plus = SafeAggregator.safe_divide(clutch_1v3_plus_wins, clutch_1v3_plus_attempts)
        
        # Clutch impact score: weighted by difficulty
        impact_score = (clutch_1v1_wins * 1.0 + clutch_1v2_wins * 3.0 + clutch_1v3_plus_wins * 7.0)
        
        return {
            'tac_clutch_1v1_attempts': clutch_1v1_attempts,
            'tac_clutch_1v1_wins': clutch_1v1_wins,
            'tac_clutch_1v1_rate': round(rate_1v1, 3),
            'tac_clutch_1v2_attempts': clutch_1v2_attempts,
            'tac_clutch_1v2_wins': clutch_1v2_wins,
            'tac_clutch_1v2_rate': round(rate_1v2, 3),
            'tac_clutch_1v3_plus_attempts': clutch_1v3_plus_attempts,
            'tac_clutch_1v3_plus_wins': clutch_1v3_plus_wins,
            'tac_clutch_1v3_plus_rate': round(rate_1v3_plus, 3),
            'tac_clutch_impact_score': round(impact_score, 2)
        }
    
    @staticmethod
    def _calculate_utility(steam_id: str, conn_l2: sqlite3.Connection) -> Dict[str, Any]:
        """
        Calculate Utility Mastery (12 columns)
        
        Columns:
        - tac_util_flash_per_round, tac_util_smoke_per_round
        - tac_util_molotov_per_round, tac_util_he_per_round
        - tac_util_usage_rate
        - tac_util_nade_dmg_per_round, tac_util_nade_dmg_per_nade
        - tac_util_flash_time_per_round, tac_util_flash_enemies_per_round
        - tac_util_flash_efficiency
        - tac_util_smoke_timing_score
        - tac_util_impact_score
        
        Note: Requires fact_round_player_economy for detailed utility stats
        """
        cursor = conn_l2.cursor()
        
        # Check if economy table exists (leetify mode)
        cursor.execute("""
            SELECT COUNT(*) FROM sqlite_master 
            WHERE type='table' AND name='fact_round_player_economy'
        """)
        
        has_economy = cursor.fetchone()[0] > 0
        
        if not has_economy:
            # Return zeros if no economy data
            return {
                'tac_util_flash_per_round': 0.0,
                'tac_util_smoke_per_round': 0.0,
                'tac_util_molotov_per_round': 0.0,
                'tac_util_he_per_round': 0.0,
                'tac_util_usage_rate': 0.0,
                'tac_util_nade_dmg_per_round': 0.0,
                'tac_util_nade_dmg_per_nade': 0.0,
                'tac_util_flash_time_per_round': 0.0,
                'tac_util_flash_enemies_per_round': 0.0,
                'tac_util_flash_efficiency': 0.0,
                'tac_util_smoke_timing_score': 0.0,
                'tac_util_impact_score': 0.0,
            }
        
        # Get total rounds for per-round calculations
        total_rounds = BaseFeatureProcessor.get_player_round_count(steam_id, conn_l2)
        if total_rounds == 0:
            total_rounds = 1
        
        # Utility usage from fact_match_players
        cursor.execute("""
            SELECT 
                SUM(util_flash_usage) as total_flash,
                SUM(util_smoke_usage) as total_smoke,
                SUM(util_molotov_usage) as total_molotov,
                SUM(util_he_usage) as total_he,
                SUM(flash_enemy) as enemies_flashed,
                SUM(damage_total) as total_damage,
                SUM(throw_harm_enemy) as nade_damage,
                COUNT(*) as matches
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        
        row = cursor.fetchone()
        total_flash = row[0] if row[0] else 0
        total_smoke = row[1] if row[1] else 0
        total_molotov = row[2] if row[2] else 0
        total_he = row[3] if row[3] else 0
        enemies_flashed = row[4] if row[4] else 0
        total_damage = row[5] if row[5] else 0
        nade_damage = row[6] if row[6] else 0
        rounds_with_data = row[7] if row[7] else 1
        
        total_nades = total_flash + total_smoke + total_molotov + total_he
        
        flash_per_round = total_flash / total_rounds
        smoke_per_round = total_smoke / total_rounds
        molotov_per_round = total_molotov / total_rounds
        he_per_round = total_he / total_rounds
        usage_rate = total_nades / total_rounds
        
        # Nade damage (HE grenade + molotov damage from throw_harm_enemy)
        nade_dmg_per_round = SafeAggregator.safe_divide(nade_damage, total_rounds)
        nade_dmg_per_nade = SafeAggregator.safe_divide(nade_damage, total_he + total_molotov)
        
        # Flash efficiency (simplified - kills per flash from match data)
        # DEPRECATED: Replaced by Enemies Blinded per Flash logic below
        # cursor.execute("""
        #     SELECT SUM(kills) as total_kills
        #     FROM fact_match_players
        #     WHERE steam_id_64 = ?
        # """, (steam_id,))
        # 
        # total_kills = cursor.fetchone()[0]
        # total_kills = total_kills if total_kills else 0
        # flash_efficiency = SafeAggregator.safe_divide(total_kills, total_flash)
        
        # Real flash data from fact_match_players
        # flash_time in L2 is TOTAL flash time (seconds), not average
        # flash_enemy is TOTAL enemies flashed
        cursor.execute("""
            SELECT 
                SUM(flash_time) as total_flash_time,
                SUM(flash_enemy) as total_enemies_flashed,
                SUM(util_flash_usage) as total_flashes_thrown
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        flash_row = cursor.fetchone()
        total_flash_time = flash_row[0] if flash_row and flash_row[0] else 0.0
        total_enemies_flashed = flash_row[1] if flash_row and flash_row[1] else 0
        total_flashes_thrown = flash_row[2] if flash_row and flash_row[2] else 0
        
        flash_time_per_round = total_flash_time / total_rounds if total_rounds > 0 else 0.0
        flash_enemies_per_round = total_enemies_flashed / total_rounds if total_rounds > 0 else 0.0
        
        # Flash Efficiency: Enemies Blinded per Flash Thrown (instead of kills per flash)
        # 100% means 1 enemy blinded per flash
        # 200% means 2 enemies blinded per flash (very good)
        flash_efficiency = SafeAggregator.safe_divide(total_enemies_flashed, total_flashes_thrown)
        
        # Smoke timing score CANNOT be calculated without bomb plant event timestamps
        # Would require: SELECT event_time FROM fact_round_events WHERE event_type = 'bomb_plant'
        # Then correlate with util_smoke_usage timing - currently no timing data for utility usage
        # Commenting out: tac_util_smoke_timing_score
        smoke_timing_score = 0.0
        
        # Taser Kills Logic (Zeus)
        # We want Attempts (shots fired) vs Kills
        # User requested to track "Equipped Count" instead of "Attempts" (shots)
        # because event logs often miss weapon_fire for taser.
        
        # We check fact_round_player_economy for has_zeus = 1
        zeus_equipped_count = 0
        if has_economy:
            cursor.execute("""
                SELECT COUNT(*) 
                FROM fact_round_player_economy
                WHERE steam_id_64 = ? AND has_zeus = 1
            """, (steam_id,))
            zeus_equipped_count = cursor.fetchone()[0] or 0
            
        # Kills still come from event logs
        # Removed tac_util_zeus_kills per user request (data not available)
        # cursor.execute("""
        #     SELECT 
        #         COUNT(CASE WHEN event_type = 'kill' AND weapon = 'taser' THEN 1 END) as kills
        #     FROM fact_round_events
        #     WHERE attacker_steam_id = ?
        # """, (steam_id,))
        # zeus_kills = cursor.fetchone()[0] or 0
        
        # Fallback: if equipped count < kills (shouldn't happen if economy data is good), fix it
        # if zeus_equipped_count < zeus_kills:
        #    zeus_equipped_count = zeus_kills

        # Utility impact score (composite)
        impact_score = (
            nade_dmg_per_round * 0.3 + 
            flash_efficiency * 2.0 + 
            usage_rate * 10.0
        )
        
        return {
            'tac_util_flash_per_round': round(flash_per_round, 2),
            'tac_util_smoke_per_round': round(smoke_per_round, 2),
            'tac_util_molotov_per_round': round(molotov_per_round, 2),
            'tac_util_he_per_round': round(he_per_round, 2),
            'tac_util_usage_rate': round(usage_rate, 2),
            'tac_util_nade_dmg_per_round': round(nade_dmg_per_round, 2),
            'tac_util_nade_dmg_per_nade': round(nade_dmg_per_nade, 2),
            'tac_util_flash_time_per_round': round(flash_time_per_round, 2),
            'tac_util_flash_enemies_per_round': round(flash_enemies_per_round, 2),
            'tac_util_flash_efficiency': round(flash_efficiency, 3),
            #'tac_util_smoke_timing_score': round(smoke_timing_score, 2), # Removed per user request
            'tac_util_impact_score': round(impact_score, 2),
            'tac_util_zeus_equipped_count': zeus_equipped_count,
            #'tac_util_zeus_kills': zeus_kills, # Removed
        }
    
    @staticmethod
    def _calculate_economy(steam_id: str, conn_l2: sqlite3.Connection) -> Dict[str, Any]:
        """
        Calculate Economy Efficiency (8 columns)
        
        Columns:
        - tac_eco_dmg_per_1k
        - tac_eco_kpr_eco_rounds, tac_eco_kd_eco_rounds
        - tac_eco_kpr_force_rounds, tac_eco_kpr_full_rounds
        - tac_eco_save_discipline
        - tac_eco_force_success_rate
        - tac_eco_efficiency_score
        
        Note: Requires fact_round_player_economy for equipment values
        """
        cursor = conn_l2.cursor()
        
        # Check if economy table exists
        cursor.execute("""
            SELECT COUNT(*) FROM sqlite_master 
            WHERE type='table' AND name='fact_round_player_economy'
        """)
        
        has_economy = cursor.fetchone()[0] > 0
        
        if not has_economy:
            # Return zeros if no economy data
            return {
                'tac_eco_dmg_per_1k': 0.0,
                'tac_eco_kpr_eco_rounds': 0.0,
                'tac_eco_kd_eco_rounds': 0.0,
                'tac_eco_kpr_force_rounds': 0.0,
                'tac_eco_kpr_full_rounds': 0.0,
                'tac_eco_save_discipline': 0.0,
                'tac_eco_force_success_rate': 0.0,
                'tac_eco_efficiency_score': 0.0,
            }
        
        # REAL economy-based performance from round-level data
        # Join fact_round_player_economy with fact_round_events to get kills/deaths per economy state
        
        # Fallback if no economy table but we want basic DMG/1k approximation from total damage / assumed average buy
        # But avg_equip_value is from economy table.
        # If no economy table, we can't do this accurately.
        
        # However, user says "Eco Dmg/1k" is 0.00.
        # If we have NO economy table, we returned early above.
        # If we reached here, we HAVE economy table (or at least check passed).
        # Let's check logic.
        
        # Get average equipment value
        cursor.execute("""
            SELECT AVG(equipment_value)
            FROM fact_round_player_economy
            WHERE steam_id_64 = ?
            AND equipment_value IS NOT NULL
            AND equipment_value > 0  -- Filter out zero equipment value rounds? Or include them?
        """, (steam_id,))
        avg_equip_val_res = cursor.fetchone()
        avg_equip_value = avg_equip_val_res[0] if avg_equip_val_res and avg_equip_val_res[0] else 4000.0
        
        # Avoid division by zero if avg_equip_value is somehow 0
        if avg_equip_value < 100: avg_equip_value = 4000.0
        
        # Get total damage and calculate dmg per $1000
        cursor.execute("""
            SELECT SUM(damage_total), SUM(round_total)
            FROM fact_match_players
            WHERE steam_id_64 = ?
        """, (steam_id,))
        damage_row = cursor.fetchone()
        total_damage = damage_row[0] if damage_row[0] else 0
        total_rounds = damage_row[1] if damage_row[1] else 1
        
        avg_dmg_per_round = SafeAggregator.safe_divide(total_damage, total_rounds)
        
        # Formula: (ADR) / (AvgSpend / 1000)
        # e.g. 80 ADR / (4000 / 1000) = 80 / 4 = 20 dmg/$1k
        dmg_per_1k = SafeAggregator.safe_divide(avg_dmg_per_round, (avg_equip_value / 1000.0))
        
        # ECO rounds: equipment_value < 2000
        cursor.execute("""
            SELECT 
                e.match_id,
                e.round_num,
                e.steam_id_64,
                COUNT(CASE WHEN fre.event_type = 'kill' AND fre.attacker_steam_id = e.steam_id_64 THEN 1 END) as kills,
                COUNT(CASE WHEN fre.event_type = 'kill' AND fre.victim_steam_id = e.steam_id_64 THEN 1 END) as deaths
            FROM fact_round_player_economy e
            LEFT JOIN fact_round_events fre ON e.match_id = fre.match_id AND e.round_num = fre.round_num
            WHERE e.steam_id_64 = ?
            AND e.equipment_value < 2000
            GROUP BY e.match_id, e.round_num, e.steam_id_64
        """, (steam_id,))
        
        eco_rounds = cursor.fetchall()
        eco_kills = sum(row[3] for row in eco_rounds)
        eco_deaths = sum(row[4] for row in eco_rounds)
        eco_round_count = len(eco_rounds)
        
        kpr_eco = SafeAggregator.safe_divide(eco_kills, eco_round_count)
        kd_eco = SafeAggregator.safe_divide(eco_kills, eco_deaths)
        
        # FORCE rounds: 2000 <= equipment_value < 3500
        cursor.execute("""
            SELECT 
                e.match_id,
                e.round_num,
                e.steam_id_64,
                COUNT(CASE WHEN fre.event_type = 'kill' AND fre.attacker_steam_id = e.steam_id_64 THEN 1 END) as kills,
                fr.winner_side,
                e.side
            FROM fact_round_player_economy e
            LEFT JOIN fact_round_events fre ON e.match_id = fre.match_id AND e.round_num = fre.round_num
            LEFT JOIN fact_rounds fr ON e.match_id = fr.match_id AND e.round_num = fr.round_num
            WHERE e.steam_id_64 = ?
            AND e.equipment_value >= 2000
            AND e.equipment_value < 3500
            GROUP BY e.match_id, e.round_num, e.steam_id_64, fr.winner_side, e.side
        """, (steam_id,))
        
        force_rounds = cursor.fetchall()
        force_kills = sum(row[3] for row in force_rounds)
        force_round_count = len(force_rounds)
        force_wins = sum(1 for row in force_rounds if row[4] == row[5])  # winner_side == player_side
        
        kpr_force = SafeAggregator.safe_divide(force_kills, force_round_count)
        force_success = SafeAggregator.safe_divide(force_wins, force_round_count)
        
        # FULL BUY rounds: equipment_value >= 3500
        cursor.execute("""
            SELECT 
                e.match_id,
                e.round_num,
                e.steam_id_64,
                COUNT(CASE WHEN fre.event_type = 'kill' AND fre.attacker_steam_id = e.steam_id_64 THEN 1 END) as kills
            FROM fact_round_player_economy e
            LEFT JOIN fact_round_events fre ON e.match_id = fre.match_id AND e.round_num = fre.round_num
            WHERE e.steam_id_64 = ?
            AND e.equipment_value >= 3500
            GROUP BY e.match_id, e.round_num, e.steam_id_64
        """, (steam_id,))
        
        full_rounds = cursor.fetchall()
        full_kills = sum(row[3] for row in full_rounds)
        full_round_count = len(full_rounds)
        
        kpr_full = SafeAggregator.safe_divide(full_kills, full_round_count)
        
        # Save discipline: ratio of eco rounds to total rounds (lower is better discipline)
        save_discipline = 1.0 - SafeAggregator.safe_divide(eco_round_count, total_rounds)
        
        # Efficiency score: weighted KPR across economy states
        efficiency_score = (kpr_eco * 1.5 + kpr_force * 1.2 + kpr_full * 1.0) / 3.7
        
        return {
            'tac_eco_dmg_per_1k': round(dmg_per_1k, 2),
            'tac_eco_kpr_eco_rounds': round(kpr_eco, 3),
            'tac_eco_kd_eco_rounds': round(kd_eco, 3),
            'tac_eco_kpr_force_rounds': round(kpr_force, 3),
            'tac_eco_kpr_full_rounds': round(kpr_full, 3),
            'tac_eco_save_discipline': round(save_discipline, 3),
            'tac_eco_force_success_rate': round(force_success, 3),
            'tac_eco_efficiency_score': round(efficiency_score, 2),
        }


def _get_default_tactical_features() -> Dict[str, Any]:
    """Return default zero values for all 44 TACTICAL features"""
    return {
        # Opening Impact (8)
        'tac_avg_fk': 0.0,
        'tac_avg_fd': 0.0,
        'tac_fk_rate': 0.0,
        'tac_fd_rate': 0.0,
        'tac_fk_success_rate': 0.0,
        'tac_entry_kill_rate': 0.0,
        'tac_entry_death_rate': 0.0,
        'tac_opening_duel_winrate': 0.0,
        # Multi-Kill (6)
        'tac_avg_2k': 0.0,
        'tac_avg_3k': 0.0,
        'tac_avg_4k': 0.0,
        'tac_avg_5k': 0.0,
        'tac_multikill_rate': 0.0,
        'tac_ace_count': 0,
        # Clutch Performance (10)
        'tac_clutch_1v1_attempts': 0,
        'tac_clutch_1v1_wins': 0,
        'tac_clutch_1v1_rate': 0.0,
        'tac_clutch_1v2_attempts': 0,
        'tac_clutch_1v2_wins': 0,
        'tac_clutch_1v2_rate': 0.0,
        'tac_clutch_1v3_plus_attempts': 0,
        'tac_clutch_1v3_plus_wins': 0,
        'tac_clutch_1v3_plus_rate': 0.0,
        'tac_clutch_impact_score': 0.0,
        # Utility Mastery (12)
        'tac_util_flash_per_round': 0.0,
        'tac_util_smoke_per_round': 0.0,
        'tac_util_molotov_per_round': 0.0,
        'tac_util_he_per_round': 0.0,
        'tac_util_usage_rate': 0.0,
        'tac_util_nade_dmg_per_round': 0.0,
        'tac_util_nade_dmg_per_nade': 0.0,
        'tac_util_flash_time_per_round': 0.0,
        'tac_util_flash_enemies_per_round': 0.0,
        'tac_util_flash_efficiency': 0.0,
        # 'tac_util_smoke_timing_score': 0.0, # Removed
        'tac_util_impact_score': 0.0,
        'tac_util_zeus_equipped_count': 0,
        # 'tac_util_zeus_kills': 0, # Removed
        # Economy Efficiency (8)
        'tac_eco_dmg_per_1k': 0.0,
        'tac_eco_kpr_eco_rounds': 0.0,
        'tac_eco_kd_eco_rounds': 0.0,
        'tac_eco_kpr_force_rounds': 0.0,
        'tac_eco_kpr_full_rounds': 0.0,
        'tac_eco_save_discipline': 0.0,
        'tac_eco_force_success_rate': 0.0,
        'tac_eco_efficiency_score': 0.0,
    }
