<?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';

function season_module_boot(): void
{
    require_login();
    require_permission('manage_seasons');
}

function season_status_options(): array
{
    return ['upcoming', 'active', 'paused', 'completed', 'cancelled'];
}

function season_list(): array
{
    return db_fetch_all(
        'SELECT s.*, COUNT(DISTINCT c.id) AS competition_count
         FROM seasons s
         LEFT JOIN competitions c ON c.season_id = s.id
         GROUP BY s.id
         ORDER BY FIELD(s.status, "active", "paused", "upcoming", "completed", "cancelled"), s.start_date DESC, s.id DESC'
    );
}

function season_shift_future_fixture_dates(int $seasonId, int $daysToShift): void
{
    if ($daysToShift <= 0) {
        return;
    }

    db_query(
        'UPDATE fixtures
         SET match_date = DATE_ADD(match_date, INTERVAL :days DAY),
             updated_at = NOW()
         WHERE season_id = :season_id
           AND match_date IS NOT NULL
           AND status IN ("scheduled", "postponed")
           AND match_date >= CURDATE()',
        [
            'days' => $daysToShift,
            'season_id' => $seasonId,
        ]
    );
}

function season_set_status(int $seasonId, string $status): void
{
    $existingSeason = find_season_or_abort($seasonId);
    $errors = [];
    $payload = validate_season_payload([
        'name' => $existingSeason['name'],
        'start_date' => $existingSeason['start_date'],
        'end_date' => $existingSeason['end_date'],
        'status' => $status,
    ], $errors, $seasonId);

    if ($errors !== []) {
        throw new RuntimeException($errors['status'] ?? 'Season status change is invalid.');
    }

    $currentStatus = (string) $existingSeason['status'];
    $pausedAt = $existingSeason['paused_at'] ?? null;

    db()->beginTransaction();

    try {
        if ($status === 'paused') {
            if ($currentStatus !== 'active') {
                throw new RuntimeException('Only active seasons can be paused.');
            }

            db_query(
                'UPDATE seasons
                 SET status = :status,
                     paused_at = NOW()
                 WHERE id = :id',
                ['status' => $status, 'id' => $seasonId]
            );
        } elseif ($status === 'active' && $currentStatus === 'paused') {
            $pausedTimestamp = $pausedAt !== null ? strtotime((string) $pausedAt) : false;
            $daysPaused = $pausedTimestamp === false ? 0 : (int) ceil((time() - $pausedTimestamp) / 86400);

            season_shift_future_fixture_dates($seasonId, max(1, $daysPaused));

            db_query(
                'UPDATE seasons
                 SET status = :status,
                     end_date = DATE_ADD(end_date, INTERVAL :days DAY),
                     paused_at = NULL
                 WHERE id = :id',
                [
                    'status' => $status,
                    'days' => max(1, $daysPaused),
                    'id' => $seasonId,
                ]
            );
        } else {
            db_query(
                'UPDATE seasons
                 SET status = :status,
                     paused_at = CASE WHEN :status = "paused" THEN NOW() ELSE NULL END
                 WHERE id = :id',
                ['status' => $status, 'id' => $seasonId]
            );
        }

        audit_log('set_season_status', 'seasons', $seasonId, ['status' => $existingSeason['status'], 'paused_at' => $existingSeason['paused_at'] ?? null], ['status' => $status]);
        db()->commit();
    } catch (Throwable $exception) {
        if (db()->inTransaction()) {
            db()->rollBack();
        }

        throw $exception;
    }
}

function get_season_by_id(int $seasonId): ?array
{
    return db_fetch_one('SELECT * FROM seasons WHERE id = :id LIMIT 1', ['id' => $seasonId]);
}

function find_season_or_abort(int $seasonId): array
{
    $season = get_season_by_id($seasonId);

    if ($season === null) {
        abort_request(404, 'Season not found', 'The requested season record does not exist.');
    }

    return $season;
}

function season_has_competitions(int $seasonId): bool
{
    return (int) db_fetch_value('SELECT COUNT(*) FROM competitions WHERE season_id = :season_id', ['season_id' => $seasonId], 0) > 0;
}

function allows_multiple_active_seasons(): bool
{
    return in_array((string) site_setting('enable_multiple_active_seasons', '0'), ['1', 'true', 'yes'], true);
}

function active_season_count(?int $excludeSeasonId = null): int
{
    $sql = 'SELECT COUNT(*) FROM seasons WHERE status = :status';
    $params = ['status' => 'active'];

    if ($excludeSeasonId !== null) {
        $sql .= ' AND id <> :exclude_id';
        $params['exclude_id'] = $excludeSeasonId;
    }

    return (int) db_fetch_value($sql, $params, 0);
}

function validate_season_payload(array $data, array &$errors, ?int $seasonId = null): array
{
    validate_required($data, [
        'name' => 'Season name',
        'start_date' => 'Start date',
        'end_date' => 'End date',
        'status' => 'Status',
    ], $errors);
    validate_date_field($data, 'start_date', 'Start date', $errors);
    validate_date_field($data, 'end_date', 'End date', $errors);
    validate_in_array_field($data, 'status', season_status_options(), 'Status', $errors);

    $normalized = [
        'name' => trim((string) ($data['name'] ?? '')),
        'start_date' => trim((string) ($data['start_date'] ?? '')),
        'end_date' => trim((string) ($data['end_date'] ?? '')),
        'status' => (string) ($data['status'] ?? 'upcoming'),
    ];

    validate_date_order($normalized['start_date'], $normalized['end_date'], 'Start date', 'End date', $errors);

    if ($normalized['name'] !== '' && duplicate_exists('seasons', 'name', $normalized['name'], $seasonId)) {
        $errors['name'] = 'Season name already exists.';
    }

    if ($normalized['status'] === 'active' && !allows_multiple_active_seasons() && active_season_count($seasonId) > 0) {
        $errors['status'] = 'Only one active season is allowed by current system settings.';
    }

    return $normalized;
}

function season_status_badge_class(string $status): string
{
    return match ($status) {
        'active' => 'badge-soft-success',
        'paused' => 'bg-warning-subtle text-warning-emphasis',
        'upcoming' => 'text-bg-light',
        'completed' => 'bg-secondary-subtle text-secondary-emphasis',
        'cancelled' => 'badge-soft-danger',
        default => 'text-bg-light',
    };
}
