<?php

require __DIR__ . "/Classes/ApiHandler.php";

use App\Classes\ApiHandler;
use GuzzleHttp\Client;

class SeasonImportHandler extends ApiHandler
{
  protected string $postgrestUrl;
  protected string $postgrestApiKey;

  private string $tmdbApiKey;
  private string $seasonsImportToken;

  public function __construct()
  {
    parent::__construct();
    $this->ensureCliAccess();
    $this->loadEnvironment();
    $this->authenticateRequest();
  }

  private function loadEnvironment(): void
  {
    $this->postgrestUrl = getenv("POSTGREST_URL") ?: $_ENV["POSTGREST_URL"];
    $this->postgrestApiKey = getenv("POSTGREST_API_KEY") ?: $_ENV["POSTGREST_API_KEY"];
    $this->tmdbApiKey = getenv("TMDB_API_KEY") ?: $_ENV["TMDB_API_KEY"];
    $this->seasonsImportToken = getenv("SEASONS_IMPORT_TOKEN") ?: $_ENV["SEASONS_IMPORT_TOKEN"];
  }

  private function authenticateRequest(): void
  {
    if ($_SERVER["REQUEST_METHOD"] !== "POST") {
      http_response_code(405);
      echo json_encode(["error" => "Method Not Allowed"]);
      exit();
    }

    $authHeader = $_SERVER["HTTP_AUTHORIZATION"] ?? "";
    if (!preg_match('/Bearer\s+(.+)/', $authHeader, $matches)) {
      http_response_code(401);
      echo json_encode(["error" => "Unauthorized"]);
      exit();
    }

    $providedToken = trim($matches[1]);
    if ($providedToken !== $this->seasonsImportToken) {
      http_response_code(403);
      echo json_encode(["error" => "Forbidden"]);
      exit();
    }
  }

  public function importSeasons(): void
  {
    $ongoingShows = $this->fetchOngoingShows();

    if (empty($ongoingShows)) {
      http_response_code(200);
      echo json_encode(["message" => "No ongoing shows to update"]);
      return;
    }

    foreach ($ongoingShows as $show) {
      $this->processShowSeasons($show);
    }

    http_response_code(200);
    echo json_encode(["message" => "Season import completed"]);
  }

  private function fetchOngoingShows(): array
  {
    return $this->fetchFromPostgREST("optimized_shows", "ongoing=eq.true", "GET");
  }

  private function processShowSeasons(array $show): void
  {
    $tmdbId = $show["tmdb_id"] ?? null;
    $showId = $show["id"] ?? null;

    if (!$tmdbId || !$showId) return;

    $tmdbShowData = $this->fetchShowDetails($tmdbId);
    $seasons = $tmdbShowData["seasons"] ?? [];
    $status = $tmdbShowData["status"] ?? "Unknown";

    if (empty($seasons) && !$this->shouldKeepOngoing($status)) {
      $this->disableOngoingStatus($showId);
      return;
    }

    foreach ($seasons as $season) {
      $this->processSeasonEpisodes($showId, $tmdbId, $season);
    }
  }

  private function shouldKeepOngoing(string $status): bool
  {
    $validStatuses = ["Returning Series", "In Production"];
    return in_array($status, $validStatuses);
  }

  private function fetchShowDetails(string $tmdbId): array
  {
    $client = new Client();
    $url = "https://api.themoviedb.org/3/tv/{$tmdbId}?api_key={$this->tmdbApiKey}&append_to_response=seasons";

    try {
      $response = $client->get($url, ["headers" => ["Accept" => "application/json"]]);
      return json_decode($response->getBody(), true) ?? [];
    } catch (\Exception $e) {
      return [];
    }
  }

  private function fetchWatchedEpisodes(int $showId): array
  {
    $watchedEpisodes = $this->fetchFromPostgREST(
      "optimized_last_watched_episodes",
      "show_id=eq.{$showId}&order=last_watched_at.desc&limit=1",
      "GET"
    );

    if (empty($watchedEpisodes)) return [];

    $lastWatched = $watchedEpisodes[0] ?? null;

    if ($lastWatched) return [
        "season_number" => (int) $lastWatched["season_number"],
        "episode_number" => (int) $lastWatched["episode_number"]
      ];

    return [];
  }

  private function processSeasonEpisodes(int $showId, string $tmdbId, array $season): void
  {
    $seasonNumber = $season["season_number"] ?? null;

    if ($seasonNumber === null || $seasonNumber == 0) return;

    $episodes = $this->fetchSeasonEpisodes($tmdbId, $seasonNumber);

    if (empty($episodes)) return;

    $watchedEpisodes = $this->fetchWatchedEpisodes($showId);
    $lastWatchedSeason = $watchedEpisodes["season_number"] ?? null;
    $lastWatchedEpisode = $watchedEpisodes["episode_number"] ?? null;
    $scheduledEpisodes = $this->fetchFromPostgREST(
        "optimized_scheduled_episodes",
        "show_id=eq.{$showId}&season_number=eq.{$seasonNumber}",
        "GET"
    );
    $scheduledEpisodeNumbers = array_column($scheduledEpisodes, "episode_number");

    foreach ($episodes as $episode) {
      $episodeNumber = $episode["episode_number"] ?? null;

      if ($episodeNumber === null) continue;
      if (in_array($episodeNumber, $scheduledEpisodeNumbers)) continue;
      if ($lastWatchedSeason !== null && $seasonNumber < $lastWatchedSeason) return;
      if ($seasonNumber == $lastWatchedSeason && $episodeNumber <= $lastWatchedEpisode) continue;

      $this->addEpisodeToSchedule($showId, $seasonNumber, $episode);
    }
  }

  private function fetchSeasonEpisodes(string $tmdbId, int $seasonNumber): array
  {
    $client = new Client();
    $url = "https://api.themoviedb.org/3/tv/{$tmdbId}/season/{$seasonNumber}?api_key={$this->tmdbApiKey}";

    try {
      $response = $client->get($url, ["headers" => ["Accept" => "application/json"]]);
      return json_decode($response->getBody(), true)["episodes"] ?? [];
    } catch (\Exception $e) {
      return [];
    }
  }

  private function addEpisodeToSchedule(int $showId, int $seasonNumber, array $episode): void
  {
    $airDate = $episode["air_date"] ?? null;

    if (!$airDate) return;

    $currentDate = date("Y-m-d");
    $status = ($airDate && $airDate < $currentDate) ? "aired" : "upcoming";

    $payload = [
      "show_id" => $showId,
      "season_number" => $seasonNumber,
      "episode_number" => $episode["episode_number"],
      "air_date" => $airDate,
      "status" => $status,
    ];

    $this->fetchFromPostgREST("scheduled_episodes", "", "POST", $payload);
  }
}

$handler = new SeasonImportHandler();
$handler->importSeasons();