/**
 * Cinemeta is the public addon that powers Stremio's catalog. The HTTP
 * surface is unauthenticated and returns IMDB-style metadata keyed by
 * IMDB id. We use it as a quiet fallback for the IMDB rating chip and
 * the IMDB-style plot when TMDB doesn't have one.
 *
 * Endpoint shape:
 *   GET https://v3-cinemeta.strem.io/meta/{type}/{imdb_id}.json
 *     where type = 'movie' | 'series'
 *
 * Response (truncated):
 *   { meta: { id, name, year, imdbRating, description, poster, cast,
 *             director, runtime, genres, country, awards, ... } }
 *
 * No SLA. Treat it as best-effort.
 */

const BASE = 'https://v3-cinemeta.strem.io'

export interface CinemetaEpisode {
  /** Synthetic id of the form `<imdb>:<season>:<episode>`. */
  id?: string
  imdb_id?: string
  season: number
  episode: number
  title?: string
  thumbnail?: string
  released?: string
  /** Episode-level IMDB rating as a string ("8.4"). May be missing. */
  imdbRating?: string
  description?: string
  /** Some payloads include episode-level director / writer. */
  director?: string[]
  writer?: string[]
}

export interface CinemetaMeta {
  id: string
  type: 'movie' | 'series'
  name: string
  year?: string
  imdbRating?: string
  description?: string
  poster?: string
  background?: string
  logo?: string
  cast?: string[]
  director?: string[]
  writer?: string[]
  runtime?: string
  genres?: string[]
  country?: string
  awards?: string
  released?: string
  trailers?: { source: string; type: string }[]
  /** Per-episode entries on series payloads. */
  videos?: CinemetaEpisode[]
}

async function fetchJson<T>(url: string): Promise<T | null> {
  try {
    const res = await fetch(url)
    if (!res.ok) return null
    return (await res.json()) as T
  } catch {
    return null
  }
}

export async function cinemetaMovie(imdbId: string): Promise<CinemetaMeta | null> {
  if (!imdbId) return null
  const data = await fetchJson<{ meta?: CinemetaMeta }>(`${BASE}/meta/movie/${encodeURIComponent(imdbId)}.json`)
  return data?.meta || null
}

export async function cinemetaSeries(imdbId: string): Promise<CinemetaMeta | null> {
  if (!imdbId) return null
  const data = await fetchJson<{ meta?: CinemetaMeta }>(`${BASE}/meta/series/${encodeURIComponent(imdbId)}.json`)
  return data?.meta || null
}

/* ──────────────────────────────────────────────────────────── */
/*  Per-episode helpers                                         */
/* ──────────────────────────────────────────────────────────── */

function epKey(season: number, episode: number): string {
  return `${season}:${episode}`
}

/**
 * Build a Map keyed by `${season}:${episode}` so callers can do O(1)
 * lookups while rendering a long episode list. Returns an empty map if
 * the meta has no `videos` array.
 */
export function buildCinemetaEpisodeMap(
  meta: CinemetaMeta | null | undefined,
): Map<string, CinemetaEpisode> {
  const out = new Map<string, CinemetaEpisode>()
  for (const v of meta?.videos || []) {
    if (Number.isFinite(v.season) && Number.isFinite(v.episode)) {
      out.set(epKey(v.season, v.episode), v)
    }
  }
  return out
}

/** Look up a single episode in the meta payload. */
export function findCinemetaEpisode(
  meta: CinemetaMeta | null | undefined,
  season: number,
  episode: number,
): CinemetaEpisode | null {
  for (const v of meta?.videos || []) {
    if (v.season === season && v.episode === episode) return v
  }
  return null
}
