<?php

namespace App\Services;

use App\Core\Database;
use PDO;

final class DemoScoresheetSeeder
{
    private PDO $db;

    public function __construct()
    {
        $this->db = Database::connection();
    }

    public function seed(int $tournamentId, bool $force = false): array
    {
        if (!$force && $this->hasDemo($tournamentId)) {
            return ['created' => false, 'message' => 'El torneo ya tiene demo de planilla'];
        }

        $this->db->beginTransaction();
        try {
            $homeTeamId = $this->team($tournamentId, 'Demo A', 'DT Demo A');
            $awayTeamId = $this->team($tournamentId, 'Demo B', 'DT Demo B');
            $homePlayers = $this->players($homeTeamId, 'A');
            $awayPlayers = $this->players($awayTeamId, 'B');
            $matchId = $this->match($tournamentId, $homeTeamId, $awayTeamId);
            $this->sets($matchId, $homeTeamId);
            $this->sheetDetails($matchId, $homeTeamId, $homePlayers[0], 'DT Demo A', 'Observaciones demo equipo A');
            $this->sheetDetails($matchId, $awayTeamId, $awayPlayers[0], 'DT Demo B', 'Observaciones demo equipo B');
            $this->libero($matchId, $homeTeamId, $homePlayers[11]);
            $this->libero($matchId, $awayTeamId, $awayPlayers[11]);
            $this->rotations($matchId, $homeTeamId, array_slice($homePlayers, 0, 6));
            $this->rotations($matchId, $awayTeamId, array_slice($awayPlayers, 0, 6));
            $this->signature($matchId);
            $this->events($matchId, $homeTeamId, $awayTeamId);
            $this->db->commit();

            return ['created' => true, 'match_id' => $matchId, 'home_team_id' => $homeTeamId, 'away_team_id' => $awayTeamId];
        } catch (\Throwable $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    private function hasDemo(int $tournamentId): bool
    {
        $stmt = $this->db->prepare('SELECT id FROM teams WHERE tournament_id = :id AND name IN ("Demo A", "Demo B") LIMIT 1');
        $stmt->execute(['id' => $tournamentId]);
        return (bool) $stmt->fetch();
    }

    private function team(int $tournamentId, string $name, string $coach): int
    {
        $stmt = $this->db->prepare('SELECT id FROM teams WHERE tournament_id = :tournament_id AND name = :name');
        $stmt->execute(['tournament_id' => $tournamentId, 'name' => $name]);
        $row = $stmt->fetch();
        if ($row) {
            return (int) $row['id'];
        }

        $stmt = $this->db->prepare(
            'INSERT INTO teams (tournament_id, name, coach_name, registration_token)
             VALUES (:tournament_id, :name, :coach_name, :registration_token)'
        );
        $stmt->execute([
            'tournament_id' => $tournamentId,
            'name' => $name,
            'coach_name' => $coach,
            'registration_token' => bin2hex(random_bytes(16)),
        ]);
        return (int) $this->db->lastInsertId();
    }

    private function players(int $teamId, string $prefix): array
    {
        $ids = [];
        $positions = ['Armador', 'Opuesto', 'Central', 'Punta', 'Punta', 'Central', 'Universal', 'Universal', 'Punta', 'Central', 'Opuesto', 'Libero'];
        for ($i = 1; $i <= 12; $i++) {
            $doc = "DEMO-$prefix-$i";
            $stmt = $this->db->prepare('SELECT id FROM players WHERE team_id = :team_id AND document_id = :doc');
            $stmt->execute(['team_id' => $teamId, 'doc' => $doc]);
            $row = $stmt->fetch();
            if ($row) {
                $ids[] = (int) $row['id'];
                continue;
            }
            $stmt = $this->db->prepare(
                'INSERT INTO players (team_id, first_name, last_name, document_id, birth_date, jersey_number, position)
                 VALUES (:team_id, :first_name, :last_name, :document_id, "1998-01-01", :jersey_number, :position)'
            );
            $stmt->execute([
                'team_id' => $teamId,
                'first_name' => "Jugador$prefix",
                'last_name' => str_pad((string) $i, 2, '0', STR_PAD_LEFT),
                'document_id' => $doc,
                'jersey_number' => $i,
                'position' => $positions[$i - 1],
            ]);
            $ids[] = (int) $this->db->lastInsertId();
        }
        return $ids;
    }

    private function match(int $tournamentId, int $homeTeamId, int $awayTeamId): int
    {
        $stmt = $this->db->prepare('SELECT id FROM matches WHERE tournament_id = :tournament_id AND home_team_id = :home AND away_team_id = :away LIMIT 1');
        $stmt->execute(['tournament_id' => $tournamentId, 'home' => $homeTeamId, 'away' => $awayTeamId]);
        $row = $stmt->fetch();
        if ($row) {
            return (int) $row['id'];
        }

        $stmt = $this->db->prepare(
            'INSERT INTO matches (tournament_id, phase, scheduled_at, home_team_id, away_team_id, status, winner_team_id, home_sets, away_sets)
             VALUES (:tournament_id, "demo", NOW(), :home, :away, "finished", :winner, 3, 1)'
        );
        $stmt->execute(['tournament_id' => $tournamentId, 'home' => $homeTeamId, 'away' => $awayTeamId, 'winner' => $homeTeamId]);
        return (int) $this->db->lastInsertId();
    }

    private function sets(int $matchId, int $winnerTeamId): void
    {
        $scores = [[25, 21], [22, 25], [25, 18], [25, 23]];
        foreach ($scores as $index => [$home, $away]) {
            $stmt = $this->db->prepare(
                'INSERT INTO match_sets (match_id, set_number, home_points, away_points, winner_team_id)
                 VALUES (:match_id, :set_number, :home, :away, :winner)
                 ON DUPLICATE KEY UPDATE home_points = VALUES(home_points), away_points = VALUES(away_points), winner_team_id = VALUES(winner_team_id)'
            );
            $stmt->execute([
                'match_id' => $matchId,
                'set_number' => $index + 1,
                'home' => $home,
                'away' => $away,
                'winner' => $home > $away ? $winnerTeamId : null,
            ]);
        }
    }

    private function sheetDetails(int $matchId, int $teamId, int $captainId, string $coach, string $observations): void
    {
        $stmt = $this->db->prepare(
            'INSERT INTO match_sheet_details (match_id, team_id, captain_player_id, coach_name, observations)
             VALUES (:match_id, :team_id, :captain, :coach, :observations)
             ON DUPLICATE KEY UPDATE captain_player_id = VALUES(captain_player_id), coach_name = VALUES(coach_name), observations = VALUES(observations)'
        );
        $stmt->execute(['match_id' => $matchId, 'team_id' => $teamId, 'captain' => $captainId, 'coach' => $coach, 'observations' => $observations]);
    }

    private function libero(int $matchId, int $teamId, int $playerId): void
    {
        $this->db->prepare(
            'INSERT IGNORE INTO match_liberos (match_id, team_id, player_id, set_number, is_starting)
             VALUES (:match_id, :team_id, :player_id, 1, 1)'
        )->execute(['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => $playerId]);
    }

    private function rotations(int $matchId, int $teamId, array $players): void
    {
        foreach ($players as $index => $playerId) {
            $this->db->prepare(
                'INSERT INTO rotations (match_id, team_id, set_number, position_number, player_id)
                 VALUES (:match_id, :team_id, 1, :position, :player_id)
                 ON DUPLICATE KEY UPDATE player_id = VALUES(player_id)'
            )->execute(['match_id' => $matchId, 'team_id' => $teamId, 'position' => $index + 1, 'player_id' => $playerId]);
        }
    }

    private function signature(int $matchId): void
    {
        $payload = ['match_id' => $matchId, 'signer_name' => 'Arbitro Demo', 'role' => 'principal'];
        $this->db->prepare(
            'INSERT INTO referee_signatures (match_id, signer_name, role, signature_hash, signed_payload)
             VALUES (:match_id, "Arbitro Demo", "principal", :hash, :payload)
             ON DUPLICATE KEY UPDATE signature_hash = VALUES(signature_hash), signed_payload = VALUES(signed_payload)'
        )->execute(['match_id' => $matchId, 'hash' => hash('sha256', json_encode($payload)), 'payload' => json_encode($payload)]);
    }

    private function events(int $matchId, int $homeTeamId, int $awayTeamId): void
    {
        foreach ([['point', $homeTeamId, 1, 25, 21], ['timeout', $awayTeamId, 1, 18, 16], ['yellow_card', $awayTeamId, 2, 10, 9]] as [$type, $teamId, $set, $home, $away]) {
            $this->db->prepare(
                'INSERT INTO match_events (match_id, set_number, team_id, event_type, points_home, points_away, notes)
                 VALUES (:match_id, :set_number, :team_id, :event_type, :home, :away, "Demo planilla")'
            )->execute(['match_id' => $matchId, 'set_number' => $set, 'team_id' => $teamId, 'event_type' => $type, 'home' => $home, 'away' => $away]);
        }
    }
}
