<?php

namespace App\Libraries;

use App\Models\FootballFixtureModel;
use App\Models\FootballLeagueModel;
use App\Models\FootballLeagueSyncLogModel;
use App\Models\FootballSettingModel;
use App\Models\FootballTeamModel;
use Config\ApiFootball;

class FootballLeagueSync
{
    protected ApiFootballClient $client;
    protected ApiFootball $config;
    protected FootballLeagueModel $leagueModel;
    protected FootballTeamModel $teamModel;
    protected FootballFixtureModel $fixtureModel;
    protected FootballLeagueSyncLogModel $syncLogModel;
    protected FootballSettingModel $settingModel;
    protected $db;

    public function __construct(
        ?ApiFootballClient $client = null,
        ?ApiFootball $config = null
    ) {
        $this->client = $client ?? new ApiFootballClient();
        $this->config = $config ?? config('ApiFootball');
        $this->leagueModel = new FootballLeagueModel();
        $this->teamModel = new FootballTeamModel();
        $this->fixtureModel = new FootballFixtureModel();
        $this->syncLogModel = new FootballLeagueSyncLogModel();
        $this->settingModel = new FootballSettingModel();
        $this->db = \Config\Database::connect();
    }

    public function syncLeagueData(int $leagueDbId, ?string $from = null, ?string $to = null, bool $force = false): array
    {
        $league = $this->leagueModel->find($leagueDbId);
        if (!$league) {
            throw new \InvalidArgumentException('League not found.');
        }

        $season = $this->settingModel->currentSeason();
        $from = $from ?? date('Y-m-d');
        $to = $to ?? date('Y-m-d', strtotime('+14 days'));

        $teamsSynced = 0;
        if ($force || !$this->syncLogModel->teamsFresh($leagueDbId, $season, $this->config->teamsCacheTtl)) {
            $teamsSynced = $this->syncTeams($league, $season);
        }

        $fixturesSynced = 0;
        if ($force || !$this->syncLogModel->fixturesFresh($leagueDbId, $season, $from, $to, $this->config->fixturesCacheTtl)) {
            $fixturesSynced = $this->syncFixtures($league, $season, $from, $to);
        }

        return [
            'teams_synced' => $teamsSynced,
            'fixtures_synced' => $fixturesSynced,
            'from' => $from,
            'to' => $to,
        ];
    }

    public function syncByApiLeagueId(int $apiLeagueId, ?string $from = null, ?string $to = null, bool $force = false): array
    {
        $league = $this->leagueModel->findByApiLeagueId($apiLeagueId);
        if (!$league) {
            throw new \InvalidArgumentException('League not in catalog. Run football:sync-reference first.');
        }

        return $this->syncLeagueData((int) $league['id'], $from, $to, $force);
    }

    public function syncTeams(array $league, int $season): int
    {
        $leagueDbId = (int) $league['id'];
        $apiLeagueId = (int) $league['api_league_id'];
        $countryName = $league['country_name'] ?? null;

        $items = $this->client->getResponseItems('teams', [
            'league' => $apiLeagueId,
            'season' => $season,
        ]);

        $count = 0;
        $now = date('Y-m-d H:i:s');

        foreach ($items as $item) {
            $team = $item['team'] ?? [];
            $teamId = $this->teamModel->upsertFromApi($team, $countryName);
            if ($teamId <= 0) {
                continue;
            }

            $exists = $this->db->table('football_league_teams')
                ->where('league_id', $leagueDbId)
                ->where('team_id', $teamId)
                ->where('season', $season)
                ->countAllResults();

            if (!$exists) {
                $this->db->table('football_league_teams')->insert([
                    'league_id' => $leagueDbId,
                    'team_id' => $teamId,
                    'season' => $season,
                    'created_at' => $now,
                ]);
            }

            $count++;
        }

        $this->syncLogModel->touchTeams($leagueDbId, $season);

        return $count;
    }

    public function syncFixtures(array $league, int $season, string $from, string $to): int
    {
        $leagueDbId = (int) $league['id'];
        $apiLeagueId = (int) $league['api_league_id'];
        $timezone = $this->settingModel->timezone();

        $this->client->throttle();
        $items = $this->client->getResponseItems('fixtures', [
            'league' => $apiLeagueId,
            'season' => $season,
            'from' => $from,
            'to' => $to,
            'timezone' => $timezone,
        ]);

        $count = 0;
        $now = date('Y-m-d H:i:s');

        foreach ($items as $item) {
            $fixture = $item['fixture'] ?? [];
            $teams = $item['teams'] ?? [];
            $apiFixtureId = (int) ($fixture['id'] ?? 0);
            if ($apiFixtureId <= 0) {
                continue;
            }

            $homeTeamId = $this->teamModel->upsertFromApi($teams['home'] ?? [], $league['country_name'] ?? null);
            $awayTeamId = $this->teamModel->upsertFromApi($teams['away'] ?? [], $league['country_name'] ?? null);

            if ($homeTeamId <= 0 || $awayTeamId <= 0) {
                continue;
            }

            $kickoffLocal = null;
            if (!empty($fixture['date'])) {
                $kickoffLocal = date('Y-m-d H:i:s', strtotime($fixture['date']));
            }

            $kickoffUtc = null;
            if (!empty($fixture['timestamp'])) {
                $kickoffUtc = gmdate('Y-m-d H:i:s', (int) $fixture['timestamp']);
            }

            $payload = [
                'api_fixture_id' => $apiFixtureId,
                'league_id' => $leagueDbId,
                'season' => $season,
                'home_team_id' => $homeTeamId,
                'away_team_id' => $awayTeamId,
                'kickoff_utc' => $kickoffUtc,
                'kickoff_local' => $kickoffLocal,
                'status_short' => $fixture['status']['short'] ?? null,
                'round' => $item['league']['round'] ?? null,
                'updated_at' => $now,
            ];

            $existing = $this->fixtureModel->findByApiFixtureId($apiFixtureId);
            if ($existing) {
                $this->fixtureModel->update($existing['id'], $payload);
            } else {
                $payload['created_at'] = $now;
                $this->fixtureModel->insert($payload);
            }

            $count++;
        }

        $this->syncLogModel->touchFixtures($leagueDbId, $season, $from, $to);

        return $count;
    }

    public function pruneOldFixtures(int $daysPast = 30, int $daysFuture = 60): int
    {
        $cutoffPast = date('Y-m-d', strtotime("-{$daysPast} days"));
        $cutoffFuture = date('Y-m-d', strtotime("+{$daysFuture} days"));

        $this->db->table('football_fixtures')
            ->groupStart()
            ->where('DATE(kickoff_local) <', $cutoffPast)
            ->orWhere('DATE(kickoff_local) >', $cutoffFuture)
            ->groupEnd()
            ->delete();

        return (int) $this->db->affectedRows();
    }
}
