<?php
/**
 * USCF Export - Tournament header (.TH) format for US Chess submission
 *
 * @package Chess_Podium
 */

if (!defined('ABSPATH')) {
    exit;
}

final class ChessPodium_USCF_Export
{
    /**
     * Generate .TH format content for tournament.
     *
     * @param int $tournamentId Tournament ID.
     * @return string .TH file content.
     */
    public static function generate_th(int $tournamentId): string
    {
        $tournament = self::get_tournament($tournamentId);
        if (!$tournament) {
            return '';
        }

        $players = self::get_players($tournamentId);
        $standings = self::compute_standings($tournamentId);
        $pairings = self::get_all_pairings($tournamentId);
        $roundsTotal = (int) ($tournament->current_round ?: $tournament->rounds_total);

        $tournamentMeta = self::get_tournament_meta($tournamentId);
        $tdCode = $tournamentMeta['uscf_td_code'] ?? '';
        $affiliate = $tournamentMeta['uscf_affiliate'] ?? '';
        $city = $tournamentMeta['uscf_city'] ?? ($tournamentMeta['venue_name'] ?? ($tournament->city ?? ''));
        $state = $tournamentMeta['uscf_state'] ?? '';
        $zip = $tournamentMeta['uscf_zip'] ?? '';
        $country = isset($tournament->country_code) && (string) $tournament->country_code !== '' ? (string) $tournament->country_code : 'US';
        $startDate = $tournamentMeta['start_date'] ?? ($tournament->start_date ?? '');
        $endDate = $tournamentMeta['end_date'] ?? ($tournament->end_date ?? $startDate);
        $timeControl = $tournamentMeta['time_control'] ?? ($tournament->time_control ?? '');

        $lines = [];

        $lines[] = 'USCF Tournament Report';
        $lines[] = '==================';
        $lines[] = '';
        $lines[] = 'Tournament: ' . (string) $tournament->name;
        $lines[] = 'City: ' . (string) $city;
        $lines[] = 'State: ' . (string) $state;
        $lines[] = 'ZIP: ' . (string) $zip;
        $lines[] = 'Country: ' . (string) $country;
        $lines[] = 'Start: ' . self::format_date_us($startDate);
        $lines[] = 'End: ' . self::format_date_us($endDate);
        $lines[] = 'Rounds: ' . $roundsTotal;
        $lines[] = 'Time Control: ' . (string) $timeControl;
        if ($tdCode !== '') {
            $lines[] = 'TD Code: ' . $tdCode;
        }
        if ($affiliate !== '') {
            $lines[] = 'Affiliate: ' . $affiliate;
        }
        $lines[] = '';

        $playerRankMap = [];
        foreach ($standings as $idx => $s) {
            $playerRankMap[(int) $s['player_id']] = $idx + 1;
        }

        $playerIdToStartRank = [];
        $startRank = 1;
        foreach ($players as $p) {
            $playerIdToStartRank[(int) $p->id] = $startRank++;
        }

        $roundResults = self::build_round_results($players, $pairings, $playerIdToStartRank);

        $lines[] = 'Players';
        $lines[] = '-------';
        foreach ($standings as $idx => $s) {
            $pid = (int) $s['player_id'];
            $player = self::find_player($players, $pid);
            if (!$player) {
                continue;
            }
            $uscfId = isset($player->uscf_id) && (string) $player->uscf_id !== '' ? (string) $player->uscf_id : '0';
            $line = sprintf(
                '%d. %s | USCF: %s | Rating: %d | Pts: %.1f',
                $idx + 1,
                self::pad_str((string) $player->name, 35),
                $uscfId,
                (int) ($player->rating ?? 0),
                (float) ($s['points'] ?? 0)
            );
            $lines[] = $line;
        }
        $lines[] = '';

        $lines[] = 'Results';
        $lines[] = '-------';
        foreach ($standings as $idx => $s) {
            $pid = (int) $s['player_id'];
            $player = self::find_player($players, $pid);
            if (!$player) {
                continue;
            }
            $roundPart = '';
            for ($r = 1; $r <= $roundsTotal; $r++) {
                $res = $roundResults[$pid][$r] ?? null;
                if ($res) {
                    if ($res['opp'] === 0 && ($res['color'] ?? '') === '-') {
                        $roundPart .= ($res['result'] === '=' ? 'BYE' : 'F') . ' ';
                    } else {
                        $resCode = $res['result'] === '1' ? 'W' : ($res['result'] === '0' ? 'L' : 'D');
                        $roundPart .= $res['opp'] . $resCode . ' ';
                    }
                } else {
                    $roundPart .= '- ';
                }
            }
            $lines[] = sprintf('%d. %s: %s', $idx + 1, (string) $player->name, trim($roundPart));
        }

        return implode("\r\n", $lines) . "\r\n";
    }

    private static function get_tournament(int $id): ?object
    {
        if (!class_exists('ChessPodiumPlugin')) {
            return null;
        }
        return ChessPodiumPlugin::get_tournament($id);
    }

    private static function get_players(int $tournamentId): array
    {
        if (!class_exists('ChessPodiumPlugin')) {
            return [];
        }
        return ChessPodiumPlugin::get_players($tournamentId);
    }

    private static function compute_standings(int $tournamentId): array
    {
        if (!class_exists('ChessPodiumPlugin')) {
            return [];
        }
        return ChessPodiumPlugin::compute_standings($tournamentId);
    }

    private static function get_all_pairings(int $tournamentId): array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'regina_pairings';
        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM $table WHERE tournament_id = %d ORDER BY round_no ASC, id ASC",
            $tournamentId
        ));
    }

    private static function get_tournament_meta(int $tournamentId): array
    {
        if (!class_exists('ChessPodium_PdfBrochure')) {
            return [];
        }
        return ChessPodium_PdfBrochure::get_all_meta($tournamentId);
    }

    private static function find_player(array $players, int $id): ?object
    {
        foreach ($players as $p) {
            if ((int) $p->id === $id) {
                return $p;
            }
        }
        return null;
    }

    private static function build_round_results(array $players, array $pairings, array $playerIdToStartRank): array
    {
        $results = [];
        foreach ($players as $p) {
            $results[(int) $p->id] = [];
        }

        foreach ($pairings as $m) {
            $wId = (int) $m->white_player_id;
            $bId = (int) $m->black_player_id;
            $round = (int) $m->round_no;
            $isBye = (int) $m->is_bye === 1;
            $res = class_exists('ChessPodiumPlugin') ? ChessPodiumPlugin::normalize_result((string) ($m->result ?? '')) : trim((string) ($m->result ?? ''));

            if ($isBye) {
                $results[$wId][$round] = ['opp' => 0, 'color' => '-', 'result' => '='];
                continue;
            }

            $wRank = $playerIdToStartRank[$wId] ?? 0;
            $bRank = $playerIdToStartRank[$bId] ?? 0;

            if (in_array($res, ['1-0', '1F'], true)) {
                $results[$wId][$round] = ['opp' => $bRank, 'color' => 'w', 'result' => '1'];
                $results[$bId][$round] = ['opp' => $wRank, 'color' => 'b', 'result' => '0'];
            } elseif (in_array($res, ['0-1', '0F'], true)) {
                $results[$wId][$round] = ['opp' => $bRank, 'color' => 'w', 'result' => '0'];
                $results[$bId][$round] = ['opp' => $wRank, 'color' => 'b', 'result' => '1'];
            } elseif ($res === '1/2-1/2') {
                $results[$wId][$round] = ['opp' => $bRank, 'color' => 'w', 'result' => '='];
                $results[$bId][$round] = ['opp' => $wRank, 'color' => 'b', 'result' => '='];
            } else {
                $results[$wId][$round] = ['opp' => $bRank, 'color' => 'w', 'result' => '-'];
                $results[$bId][$round] = ['opp' => $wRank, 'color' => 'b', 'result' => '-'];
            }
        }
        return $results;
    }

    private static function format_date_us(string $date): string
    {
        if ($date === '') {
            return date('m/d/Y');
        }
        $ts = strtotime($date);
        if ($ts === false) {
            return date('m/d/Y');
        }
        return date('m/d/Y', $ts);
    }

    private static function pad_str(string $s, int $len): string
    {
        $s = mb_substr($s, 0, $len);
        return str_pad($s, $len, ' ', STR_PAD_RIGHT);
    }
}
