from web.database import query_db

class FeatureService:
    @staticmethod
    def get_player_features(steam_id):
        sql = "SELECT * FROM dm_player_features WHERE steam_id_64 = ?"
        return query_db('l3', sql, [steam_id], one=True)
        
    @staticmethod
    def get_players_list(page=1, per_page=20, sort_by='rating', search=None):
        offset = (page - 1) * per_page
        
        # Sort Mapping
        sort_map = {
            'rating': 'basic_avg_rating',
            'kd': 'basic_avg_kd',
            'kast': 'basic_avg_kast',
            'matches': 'matches_played' 
        }
        order_col = sort_map.get(sort_by, 'basic_avg_rating')
        
        from web.services.stats_service import StatsService
        
        # Helper to attach match counts
        def attach_match_counts(player_list):
            if not player_list:
                return
            ids = [p['steam_id_64'] for p in player_list]
            # Batch query for counts from L2
            placeholders = ','.join('?' for _ in ids)
            sql = f"""
                SELECT steam_id_64, COUNT(*) as cnt 
                FROM fact_match_players 
                WHERE steam_id_64 IN ({placeholders}) 
                GROUP BY steam_id_64
            """
            counts = query_db('l2', sql, ids)
            cnt_dict = {r['steam_id_64']: r['cnt'] for r in counts}
            for p in player_list:
                p['matches_played'] = cnt_dict.get(p['steam_id_64'], 0)

        if search:
            # ... existing search logic ...
            # Get all matching players
            l2_players, _ = StatsService.get_players(page=1, per_page=100, search=search)
            if not l2_players:
                return [], 0
            
            # ... (Merge logic) ...
            # I need to insert the match count logic inside the merge loop or after
            
            steam_ids = [p['steam_id_64'] for p in l2_players]
            placeholders = ','.join('?' for _ in steam_ids)
            sql = f"SELECT * FROM dm_player_features WHERE steam_id_64 IN ({placeholders})"
            features = query_db('l3', sql, steam_ids)
            f_dict = {f['steam_id_64']: f for f in features}
            
            # Get counts for sorting
            count_sql = f"SELECT steam_id_64, COUNT(*) as cnt FROM fact_match_players WHERE steam_id_64 IN ({placeholders}) GROUP BY steam_id_64"
            counts = query_db('l2', count_sql, steam_ids)
            cnt_dict = {r['steam_id_64']: r['cnt'] for r in counts}

            merged = []
            for p in l2_players:
                f = f_dict.get(p['steam_id_64'])
                m = dict(p)
                if f:
                    m.update(dict(f))
                else:
                    # Fallback Calc
                    stats = StatsService.get_player_basic_stats(p['steam_id_64'])
                    if stats:
                        m['basic_avg_rating'] = stats['rating']
                        m['basic_avg_kd'] = stats['kd']
                        m['basic_avg_kast'] = stats['kast']
                    else:
                        m['basic_avg_rating'] = 0
                        m['basic_avg_kd'] = 0
                        m['basic_avg_kast'] = 0 # Ensure kast exists
                
                m['matches_played'] = cnt_dict.get(p['steam_id_64'], 0)
                merged.append(m)
            
            merged.sort(key=lambda x: x.get(order_col, 0) or 0, reverse=True)
            
            total = len(merged)
            start = (page - 1) * per_page
            end = start + per_page
            return merged[start:end], total
            
        else:
            # Browse mode
            # Check L3
            l3_count = query_db('l3', "SELECT COUNT(*) as cnt FROM dm_player_features", one=True)['cnt']
            
            if l3_count == 0 or sort_by == 'matches': 
                # If sorting by matches, we MUST use L2 counts because L3 might not have it or we want dynamic.
                # OR if L3 is empty.
                # Since L3 schema is unknown regarding 'matches_played', let's assume we fallback to L2 logic 
                # but paginated in memory if dataset is small, or just fetch all L2 players?
                # Fetching all L2 players is bad if many.
                # But for 'matches' sort, we need to know counts for ALL to sort correctly.
                # Solution: Query L2 for top N players by match count.
                
                if sort_by == 'matches':
                    # Query L2 for IDs ordered by count
                    sql = """
                        SELECT steam_id_64, COUNT(*) as cnt 
                        FROM fact_match_players 
                        GROUP BY steam_id_64 
                        ORDER BY cnt DESC 
                        LIMIT ? OFFSET ?
                    """
                    top_ids = query_db('l2', sql, [per_page, offset])
                    if not top_ids:
                        return [], 0
                        
                    total = query_db('l2', "SELECT COUNT(DISTINCT steam_id_64) as cnt FROM fact_match_players", one=True)['cnt']
                    
                    ids = [r['steam_id_64'] for r in top_ids]
                    # Fetch details for these IDs
                    l2_players = StatsService.get_players_by_ids(ids)
                    
                    # Merge logic (reuse)
                    merged = []
                    # Fetch L3 features for these IDs to show stats
                    p_ph = ','.join('?' for _ in ids)
                    f_sql = f"SELECT * FROM dm_player_features WHERE steam_id_64 IN ({p_ph})"
                    features = query_db('l3', f_sql, ids)
                    f_dict = {f['steam_id_64']: f for f in features}
                    
                    cnt_dict = {r['steam_id_64']: r['cnt'] for r in top_ids}
                    
                    # Map L2 players to dict for easy access (though list order matters for sort?)
                    # Actually top_ids is sorted.
                    p_dict = {p['steam_id_64']: p for p in l2_players}
                    
                    for r in top_ids: # Preserve order
                        sid = r['steam_id_64']
                        p = p_dict.get(sid)
                        if not p: continue
                        
                        m = dict(p)
                        f = f_dict.get(sid)
                        if f:
                            m.update(dict(f))
                        else:
                            stats = StatsService.get_player_basic_stats(sid)
                            if stats:
                                m['basic_avg_rating'] = stats['rating']
                                m['basic_avg_kd'] = stats['kd']
                                m['basic_avg_kast'] = stats['kast']
                            else:
                                m['basic_avg_rating'] = 0
                                m['basic_avg_kd'] = 0
                                m['basic_avg_kast'] = 0
                        
                        m['matches_played'] = r['cnt']
                        merged.append(m)
                        
                    return merged, total

                # L3 empty fallback (existing logic)
                l2_players, total = StatsService.get_players(page, per_page, sort_by=None) 
                merged = []
                attach_match_counts(l2_players) # Helper
                
                for p in l2_players:
                    m = dict(p)
                    stats = StatsService.get_player_basic_stats(p['steam_id_64'])
                    if stats:
                        m['basic_avg_rating'] = stats['rating']
                        m['basic_avg_kd'] = stats['kd']
                        m['basic_avg_kast'] = stats['kast']
                    else:
                        m['basic_avg_rating'] = 0
                        m['basic_avg_kd'] = 0
                        m['basic_avg_kast'] = 0
                    m['matches_played'] = p.get('matches_played', 0)
                    merged.append(m)
                
                if sort_by != 'rating': 
                    merged.sort(key=lambda x: x.get(order_col, 0) or 0, reverse=True)
                
                return merged, total

            # Normal L3 browse (sort by rating/kd/kast)
            sql = f"SELECT * FROM dm_player_features ORDER BY {order_col} DESC LIMIT ? OFFSET ?"
            features = query_db('l3', sql, [per_page, offset])
            
            total = query_db('l3', "SELECT COUNT(*) as cnt FROM dm_player_features", one=True)['cnt']
            
            if not features:
                return [], total
                
            steam_ids = [f['steam_id_64'] for f in features]
            l2_players = StatsService.get_players_by_ids(steam_ids)
            p_dict = {p['steam_id_64']: p for p in l2_players}
            
            merged = []
            for f in features:
                m = dict(f)
                p = p_dict.get(f['steam_id_64'])
                if p:
                    m.update(dict(p))
                else:
                    m['username'] = f['steam_id_64'] # Fallback
                    m['avatar_url'] = None
                merged.append(m)
                
            return merged, total

    @staticmethod
    def get_top_players(limit=20, sort_by='basic_avg_rating'):
        # Safety check for sort_by to prevent injection
        allowed_sorts = ['basic_avg_rating', 'basic_avg_kd', 'basic_avg_kast', 'basic_avg_rws']
        if sort_by not in allowed_sorts:
            sort_by = 'basic_avg_rating'
            
        sql = f"""
            SELECT f.*, p.username, p.avatar_url 
            FROM dm_player_features f
            LEFT JOIN l2.dim_players p ON f.steam_id_64 = p.steam_id_64
            ORDER BY {sort_by} DESC
            LIMIT ?
        """
        # Note: Cross-database join (l2.dim_players) works in SQLite if attached.
        # But `query_db` connects to one DB. 
        # Strategy: Fetch features, then fetch player infos from L2. Or attach DB.
        # Simple strategy: Fetch features, then extract steam_ids and batch fetch from L2 in StatsService.
        # Or simpler: Just return features and let the controller/template handle the name/avatar via another call or pre-fetching.
        
        # Actually, for "Player List" view, we really want L3 data joined with L2 names.
        # I will change this to just return features for now, and handle joining in the route handler or via a helper that attaches databases.
        # Attaching is better.
        
        return query_db('l3', f"SELECT * FROM dm_player_features ORDER BY {sort_by} DESC LIMIT ?", [limit])

    @staticmethod
    def get_player_trend(steam_id, limit=30):
        # This requires `fact_match_features` or querying L2 matches for historical data.
        # WebRDD says: "Trend graph: Recent 10/20 matches Rating trend (Chart.js)."
        # We can get this from L2 fact_match_players.
        sql = """
            SELECT m.start_time, mp.rating, mp.kd_ratio, mp.adr, m.match_id
            FROM fact_match_players mp
            JOIN fact_matches m ON mp.match_id = m.match_id
            WHERE mp.steam_id_64 = ?
            ORDER BY m.start_time DESC
            LIMIT ?
        """
        # This query needs to run against L2. 
        # So this method should actually be in StatsService or FeatureService connecting to L2.
        # I will put it here but note it uses L2. Actually, better to put in StatsService if it uses L2 tables.
        # But FeatureService conceptualizes "Trends". I'll move it to StatsService for implementation correctness (DB context).
        pass
