Files
JKTV-online/web/services/team_performance_service.py

174 lines
5.6 KiB
Python

import json
from web.database import query_db
from web.services.roster_version_service import RosterVersionService
from web.services.team_context_service import TeamContextService
class TeamPerformanceService:
@staticmethod
def _player_identity_map(steam_ids):
if not steam_ids:
return {}
placeholders = ','.join('?' for _ in steam_ids)
rows = query_db(
'l2',
f"""
SELECT steam_id_64, username, avatar_url
FROM dim_players
WHERE steam_id_64 IN ({placeholders})
""",
steam_ids,
)
return {str(row['steam_id_64']): dict(row) for row in rows}
@staticmethod
def get_team_summary():
roster_ids = TeamContextService.get_active_roster_ids()
if not roster_ids:
return {
'matches': 0,
'wins': 0,
'win_rate': 0,
'avg_rating': 0,
'maps': [],
}
placeholders = ','.join('?' for _ in roster_ids)
rows = query_db(
'l2',
f"""
SELECT
p.match_id,
CASE
WHEN p.group_id IN (1, 2) THEN p.group_id
WHEN p.team_id IN (1, 2) THEN p.team_id
END AS team_key,
COUNT(DISTINCT p.steam_id_64) AS roster_count,
AVG(p.rating) AS avg_rating,
MAX(p.is_win) AS is_win,
m.map_name,
m.start_time
FROM fact_match_players p
JOIN fact_matches m ON m.match_id = p.match_id
WHERE p.steam_id_64 IN ({placeholders})
GROUP BY p.match_id, team_key
HAVING roster_count >= 2 AND team_key IS NOT NULL
ORDER BY m.start_time DESC
""",
roster_ids,
)
matches = len(rows)
wins = sum(int(row['is_win'] or 0) for row in rows)
map_stats = {}
for row in rows:
item = map_stats.setdefault(
row['map_name'] or 'Unknown',
{'map_name': row['map_name'] or 'Unknown', 'matches': 0, 'wins': 0},
)
item['matches'] += 1
item['wins'] += int(row['is_win'] or 0)
maps = []
for item in map_stats.values():
item['win_rate'] = item['wins'] / item['matches']
maps.append(item)
maps.sort(key=lambda item: item['matches'], reverse=True)
return {
'matches': matches,
'wins': wins,
'losses': matches - wins,
'win_rate': wins / matches if matches else 0,
'avg_rating': (
sum(float(row['avg_rating'] or 0) for row in rows) / matches
if matches else 0
),
'maps': maps,
}
@staticmethod
def get_current_roster():
members = RosterVersionService.get_current_members()
identities = TeamPerformanceService._player_identity_map(
[member['steam_id_64'] for member in members]
)
result = []
for member in members:
item = dict(member)
item.update(identities.get(str(member['steam_id_64']), {}))
result.append(item)
return result
@staticmethod
def get_top_duos(limit=12):
rows = query_db(
'l3',
"""
SELECT *
FROM dm_duo_stats
ORDER BY sample_reliable DESC, matches DESC,
win_rate DESC, avg_combined_rating DESC
LIMIT ?
""",
[limit],
)
steam_ids = {
str(value)
for row in rows
for value in (row['steam_id_a'], row['steam_id_b'])
}
identities = TeamPerformanceService._player_identity_map(sorted(steam_ids))
result = []
for row in rows:
item = dict(row)
item['player_a'] = identities.get(str(row['steam_id_a']), {})
item['player_b'] = identities.get(str(row['steam_id_b']), {})
result.append(item)
return result
@staticmethod
def get_top_lineups(player_count=None, limit=12):
args = []
where = ''
if player_count:
where = 'WHERE player_count = ?'
args.append(int(player_count))
args.append(limit)
rows = query_db(
'l3',
f"""
SELECT *
FROM dm_lineup_stats
{where}
ORDER BY sample_reliable DESC, matches DESC,
win_rate DESC, avg_team_rating DESC
LIMIT ?
""",
args,
)
all_ids = set()
parsed = []
for row in rows:
item = dict(row)
item['player_ids'] = [
str(value) for value in json.loads(item['player_ids_json'])
]
all_ids.update(item['player_ids'])
parsed.append(item)
identities = TeamPerformanceService._player_identity_map(sorted(all_ids))
for item in parsed:
item['players'] = [
identities.get(steam_id, {'username': steam_id})
for steam_id in item['player_ids']
]
return parsed
@staticmethod
def get_dashboard():
return {
'summary': TeamPerformanceService.get_team_summary(),
'roster': TeamPerformanceService.get_current_roster(),
'versions': RosterVersionService.list_versions(),
'duos': TeamPerformanceService.get_top_duos(),
'lineups': TeamPerformanceService.get_top_lineups(),
}