<?php

declare(strict_types=1);

require_once dirname(__DIR__, 2) . '/core/auth.php';
require_once dirname(__DIR__, 2) . '/core/csrf.php';
require_once dirname(__DIR__, 2) . '/core/validation.php';
require_once dirname(__DIR__, 2) . '/core/audit.php';
require_once dirname(__DIR__) . '/fixtures/helpers.php';

function table_module_boot(): void
{
    require_login();
    require_permission('manage_table');
}

function can_recalculate_table(): bool
{
    return can('recalculate_table');
}

function table_competition_options(): array
{
    return db_fetch_all(
        'SELECT c.id, c.name, c.type, c.status, c.season_id, c.tie_breaker_type, s.name AS season_name
         FROM competitions c
         INNER JOIN seasons s ON s.id = c.season_id
         ORDER BY FIELD(c.status, "active", "paused", "open", "draft", "completed", "cancelled"), s.start_date DESC, c.sequence_order ASC, c.name ASC'
    );
}

function table_competition_by_id(int $competitionId): ?array
{
    return db_fetch_one(
        'SELECT c.*, s.name AS season_name
         FROM competitions c
         INNER JOIN seasons s ON s.id = c.season_id
         WHERE c.id = :id
         LIMIT 1',
        ['id' => $competitionId]
    );
}

function table_validate_competition(int $competitionId, array &$errors): ?array
{
    $competition = table_competition_by_id($competitionId);

    if ($competition === null) {
        $errors['competition_id'] = 'Selected competition is invalid.';
        return null;
    }

    if (!in_array((string) ($competition['type'] ?? ''), ['league', 'group_stage', 'mixed'], true)) {
        $errors['competition_id'] = 'Standings are only available for league, group-stage, or mixed competitions.';
        return null;
    }

    return $competition;
}

function group_stage_table_rows(int $competitionId): array
{
    return fixture_group_stage_standings($competitionId);
}

function knockout_stage_rows(int $competitionId): array
{
    $fixtures = fixture_knockout_round_rows($competitionId);
    $grouped = [];

    foreach ($fixtures as $fixture) {
        $round = (string) ($fixture['knockout_round'] ?: 'Knockout round');
        $grouped[$round][] = $fixture;
    }

    return $grouped;
}

function league_table_rows(int $competitionId): array
{
    return db_fetch_all(
        'SELECT lt.*, c.name AS club_name, c.short_name AS club_short_name
         FROM league_table lt
         INNER JOIN clubs c ON c.id = lt.club_id
         WHERE lt.competition_id = :competition_id
         ORDER BY lt.position ASC, lt.points DESC, lt.goal_difference DESC, lt.goals_for DESC, c.name ASC',
        ['competition_id' => $competitionId]
    );
}

function recalculate_league_table(int $competitionId): int
{
    $competition = table_competition_by_id($competitionId);

    if ($competition === null) {
        throw new RuntimeException('Competition not found.');
    }

    if (($competition['type'] ?? '') !== 'league') {
        throw new RuntimeException('Only league competitions can have a league table recalculated.');
    }

    $fixtures = db_fetch_all(
        'SELECT f.id, f.competition_id, f.season_id, f.home_club_id, f.away_club_id,
                mr.home_score, mr.away_score, mr.result_status
         FROM fixtures f
         INNER JOIN match_results mr ON mr.fixture_id = f.id
         WHERE f.competition_id = :competition_id
           AND mr.result_status = "verified"
         ORDER BY COALESCE(f.match_date, "9999-12-31") ASC, COALESCE(f.match_time, "23:59:59") ASC, f.matchday ASC, f.id ASC',
        ['competition_id' => $competitionId]
    );

    $clubRows = db_fetch_all(
        'SELECT DISTINCT c.id, c.name
         FROM clubs c
         INNER JOIN fixtures f ON f.home_club_id = c.id OR f.away_club_id = c.id
         WHERE f.competition_id = :competition_id
         ORDER BY c.name ASC',
        ['competition_id' => $competitionId]
    );

    $seasonId = (int) $competition['season_id'];
    $standings = [];

    foreach ($clubRows as $club) {
        $clubId = (int) $club['id'];
        $standings[$clubId] = [
            'competition_id' => $competitionId,
            'season_id' => $seasonId,
            'club_id' => $clubId,
            'played' => 0,
            'won' => 0,
            'drawn' => 0,
            'lost' => 0,
            'goals_for' => 0,
            'goals_against' => 0,
            'goal_difference' => 0,
            'points' => 0,
            'form' => '',
        ];
    }

    $pointsWin = (int) ($competition['points_win'] ?? site_setting('points_win', 3));
    $pointsDraw = (int) ($competition['points_draw'] ?? site_setting('points_draw', 1));
    $pointsLoss = (int) ($competition['points_loss'] ?? site_setting('points_loss', 0));

    foreach ($fixtures as $fixture) {
        $homeClubId = (int) $fixture['home_club_id'];
        $awayClubId = (int) $fixture['away_club_id'];

        if (!isset($standings[$homeClubId], $standings[$awayClubId])) {
            continue;
        }

        $homeScore = (int) $fixture['home_score'];
        $awayScore = (int) $fixture['away_score'];

        $standings[$homeClubId]['played']++;
        $standings[$awayClubId]['played']++;
        $standings[$homeClubId]['goals_for'] += $homeScore;
        $standings[$homeClubId]['goals_against'] += $awayScore;
        $standings[$awayClubId]['goals_for'] += $awayScore;
        $standings[$awayClubId]['goals_against'] += $homeScore;

        if ($homeScore > $awayScore) {
            $standings[$homeClubId]['won']++;
            $standings[$awayClubId]['lost']++;
            $standings[$homeClubId]['points'] += $pointsWin;
            $standings[$awayClubId]['points'] += $pointsLoss;
            $standings[$homeClubId]['form'] .= 'W';
            $standings[$awayClubId]['form'] .= 'L';
        } elseif ($homeScore < $awayScore) {
            $standings[$awayClubId]['won']++;
            $standings[$homeClubId]['lost']++;
            $standings[$awayClubId]['points'] += $pointsWin;
            $standings[$homeClubId]['points'] += $pointsLoss;
            $standings[$homeClubId]['form'] .= 'L';
            $standings[$awayClubId]['form'] .= 'W';
        } else {
            $standings[$homeClubId]['drawn']++;
            $standings[$awayClubId]['drawn']++;
            $standings[$homeClubId]['points'] += $pointsDraw;
            $standings[$awayClubId]['points'] += $pointsDraw;
            $standings[$homeClubId]['form'] .= 'D';
            $standings[$awayClubId]['form'] .= 'D';
        }
    }

    foreach ($standings as &$row) {
        $row['goal_difference'] = $row['goals_for'] - $row['goals_against'];
        $row['form'] = substr($row['form'], -5);
    }
    unset($row);

    uasort(
        $standings,
        static function (array $left, array $right): int {
            return [$right['points'], $right['goal_difference'], $right['goals_for'], $left['club_id']]
                <=> [$left['points'], $left['goal_difference'], $left['goals_for'], $right['club_id']];
        }
    );

    $pdo = db();
    $pdo->beginTransaction();

    try {
        db_query('DELETE FROM league_table WHERE competition_id = :competition_id', ['competition_id' => $competitionId]);

        $position = 1;
        foreach ($standings as $row) {
            db_query(
                'INSERT INTO league_table (
                    competition_id, season_id, club_id, played, won, drawn, lost,
                    goals_for, goals_against, goal_difference, points, position, form, updated_at
                 ) VALUES (
                    :competition_id, :season_id, :club_id, :played, :won, :drawn, :lost,
                    :goals_for, :goals_against, :goal_difference, :points, :position, :form, NOW()
                 )',
                $row + ['position' => $position++]
            );
        }

        $pdo->commit();
    } catch (Throwable $throwable) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        throw $throwable;
    }

    return count($standings);
}

function table_form_badge_class(string $symbol): string
{
    return match ($symbol) {
        'W' => 'badge-soft-success',
        'D' => 'text-bg-light',
        'L' => 'badge-soft-danger',
        default => 'text-bg-light',
    };
}
