import { query, withTransaction } from '../db/client';
import { fetchAllMatches, fetchFinishedMatches } from './footballApi';
import { calculatePoints } from './pointsService';
import { FootballApiMatch } from '../types';
import { logger } from './logger';

/**
 * Synchronisiert alle WM-Spiele von football-data.org in die Datenbank.
 * Legt neue Spiele an und aktualisiert bestehende (Status + Score).
 *
 * Sollte täglich per Cron laufen, oder manuell getriggert werden.
 */
export const syncMatches = async (): Promise<{
  total: number;
  created: number;
  updated: number;
}> => {
  logger.info('Starting match sync...');
  const startTime = Date.now();

  let created = 0;
  let updated = 0;

  try {
    const apiMatches = await fetchAllMatches();

    await withTransaction(async (client) => {
      for (const match of apiMatches) {
        const existing = await client.query<{ id: number; status: string }>(
          'SELECT id, status FROM matches WHERE external_id = $1',
          [match.id]
        );

        if (existing.rows.length === 0) {
          // Neues Spiel anlegen
          await client.query(
            `INSERT INTO matches (
              external_id, utc_date, status, stage, group_name,
              home_team_id, away_team_id,
              home_team_name, away_team_name,
              home_team_short, away_team_short,
              home_team_crest, away_team_crest,
              score_home, score_away
            ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)`,
            [
              match.id,
              match.utcDate,
              match.status,
              match.stage,
              match.group,
              match.homeTeam?.id ?? null,
              match.awayTeam?.id ?? null,
              match.homeTeam?.name ?? 'TBD',
              match.awayTeam?.name ?? 'TBD',
              match.homeTeam?.shortName || match.homeTeam?.tla || 'TBD',
              match.awayTeam?.shortName || match.awayTeam?.tla || 'TBD',
              match.homeTeam?.crest ?? null,
              match.awayTeam?.crest ?? null,
              match.score.fullTime.home,
              match.score.fullTime.away,
            ]
          );
          created++;
        } else {
          // Bestehendes Spiel aktualisieren
          await client.query(
            `UPDATE matches SET
              status = $1,
              score_home = $2,
              score_away = $3,
              utc_date = $4
            WHERE external_id = $5`,
            [
              match.status,
              match.score.fullTime.home,
              match.score.fullTime.away,
              match.utcDate,
              match.id,
            ]
          );
          updated++;
        }
      }
    });

    // Sync-Log schreiben
    await query(
      `INSERT INTO sync_log (matches_total, matches_new, matches_upd, status)
       VALUES ($1, $2, $3, 'success')`,
      [apiMatches.length, created, updated]
    );

    const duration = Date.now() - startTime;
    logger.info(`Match sync completed in ${duration}ms`, {
      total: apiMatches.length,
      created,
      updated,
    });

    return { total: apiMatches.length, created, updated };
  } catch (error) {
    // Fehler loggen
    await query(
      `INSERT INTO sync_log (matches_total, matches_new, matches_upd, status, error_msg)
       VALUES (0, 0, 0, 'error', $1)`,
      [(error as Error).message]
    ).catch(() => {}); // Fehler beim Fehler-Logging ignorieren

    logger.error('Match sync failed', { error });
    throw error;
  }
};

/**
 * Wertet Tipps für alle abgeschlossenen Spiele aus.
 * Berechnet Punkte und aktualisiert die tips-Tabelle.
 * Refreshed danach die Leaderboard Materialized View.
 *
 * Sollte nach jedem abgeschlossenen Spiel laufen.
 */
export const evaluateTips = async (): Promise<{
  matchesEvaluated: number;
  tipsUpdated: number;
}> => {
  logger.info('Starting tip evaluation...');

  // Alle abgeschlossenen Spiele mit noch nicht ausgewerteten Tipps
  const pendingMatches = await query<{
    match_id: number;
    score_home: number;
    score_away: number;
  }>(
    `SELECT DISTINCT m.id AS match_id, m.score_home, m.score_away
     FROM matches m
     JOIN tips t ON t.match_id = m.id
     WHERE m.status = 'FINISHED'
       AND m.score_home IS NOT NULL
       AND m.score_away IS NOT NULL
       AND t.points IS NULL`
  );

  let tipsUpdated = 0;

  for (const match of pendingMatches) {
    // Alle Tipps für dieses Spiel
    const tips = await query<{
      id: number;
      tip_home: number;
      tip_away: number;
    }>(
      'SELECT id, tip_home, tip_away FROM tips WHERE match_id = $1 AND points IS NULL',
      [match.match_id]
    );

    for (const tip of tips) {
      const { points } = calculatePoints(
        { home: tip.tip_home, away: tip.tip_away },
        { home: match.score_home, away: match.score_away }
      );

      await query('UPDATE tips SET points = $1 WHERE id = $2', [points, tip.id]);
      tipsUpdated++;
    }
  }

  // Leaderboard Materialized View aktualisieren
  if (tipsUpdated > 0) {
    await query('REFRESH MATERIALIZED VIEW CONCURRENTLY leaderboard');
    logger.info(`Leaderboard refreshed after evaluating ${tipsUpdated} tips`);
  }

  return {
    matchesEvaluated: pendingMatches.length,
    tipsUpdated,
  };
};
