/**
 * Empire Cinemas scraper (Lebanon)
 *
 * Tech: Next.js App Router + RSC; data served via REST API at lb-cron.empirecinemas.com
 *
 * API:
 *   Base: https://lb-cron.empirecinemas.com
 *   Auth: Bearer JWT (permanent app token, issued 2023)
 *
 *   GET /api/cinema/admin/now-showing-confirmed-list/bffv1?cinema_id={id}&date={YYYY-MM-DD}&lang_id=1
 *     → movie list with metadata (poster in altMovieContent[].artwork, runtime, genre, rating)
 *
 *   GET /api/cinema/admin/movie-confirmed-list-all?cinema_id={id}&date={YYYY-MM-DD}&lang_id=1
 *     → all showtime sessions for that cinema+date
 *     → key fields: ss_id, ss_start_show_time ("HH:MM"), ss_actual_start_date ("YYYY-MM-DD"),
 *                   mf_name (format), lang_name, sub_lang_1_name, mrrdr_runtime
 *
 * Cinema IDs (Lebanon):
 *   1 = Premiere Sodeco (Sodeco Square, Beirut)
 *   2 = The Spot Choueifat
 *
 * Booking: NOT available for Lebanon — gogo_ss_id=0, mycinema_booking_type_id=0
 */

import type { ScraperEnv, ScraperResult, ScrapedTitle, ScrapedShowtime } from '../types';
import { fetchWithTimeout } from '../utils/http';

const API_BASE = 'https://lb-cron.empirecinemas.com';

// Permanent app JWT — hardcoded in the Empire frontend bundle (chunk 9307)
const JWT = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6ImU5MjliZTFmLTI1ZWMtNGQwNy05ZDZhLTZhY2U4MDFkMTY4MCIsImlhdCI6MTY5MzY2ODcyMX0.vQVV834q_Jfei7b7OL6hM6rFuL6Z1i1PxLhRqY_A9VE';

interface CinemaConfig {
  externalId: number;
  cinemaId: string; // Our DB ID
}

export const DEFAULT_CINEMAS: CinemaConfig[] = [
  { externalId: 1, cinemaId: 'empire-sodeco' },
  { externalId: 2, cinemaId: 'empire-verdun' }, // Les Dunes / The Spot area
];

// Response types
interface NowShowingRecord {
  movie_id: number;
  movie_title: string;
  mrrdr_runtime: number;
  rating: string;
  genre_name: string;
  available_dates: string; // comma-separated "YYYY-MM-DD"
  altMovieContent?: Array<{
    artwork: string;
    lang_name: string;
    mc_plot?: string;
    mc_title?: string;
  }>;
}

interface SessionRecord {
  ss_id: number;
  movie_id: number;
  movie_title: string;
  mrrdr_runtime: number;
  mf_name: string;             // format e.g. "2D", "Digital 2D"
  lang_name: string;           // audio language
  sub_lang_1_name: string | null;
  ss_start_show_time: string;  // "HH:MM"
  ss_actual_start_date: string;// "YYYY-MM-DD"
  screen_type_name: string;    // "STANDARD", "IMAX", etc.
  ss_show_status: number;      // 16 = active
}

interface EmpireOpts {
  apiBase?: string;
  cinemas?: CinemaConfig[];
}

export async function scrapeEmpireCinemas(env: ScraperEnv, opts?: EmpireOpts): Promise<ScraperResult> {
  const resolvedApiBase = opts?.apiBase ?? API_BASE;
  const cinemas = opts?.cinemas ?? DEFAULT_CINEMAS;
  const movies: Map<string, ScrapedTitle> = new Map();
  const showtimeMap: Map<string, ScrapedShowtime> = new Map(); // deduplicate by id
  const errors: string[] = [];

  const today = new Date();
  const dates: string[] = [];
  for (let i = 0; i < 3; i++) {
    const d = new Date(today);
    d.setUTCDate(d.getUTCDate() + i);
    dates.push(d.toISOString().slice(0, 10));
  }

  for (const cinema of cinemas) {
    try {
      // Step 1: Get movie metadata (with posters) for today
      const nowShowing = await empireGet<{ Records: { data: NowShowingRecord[] } }>(
        `/api/cinema/admin/now-showing-confirmed-list/bffv1?cinema_id=${cinema.externalId}&date=${dates[0]}&lang_id=1`, resolvedApiBase
      );

      const movieMeta: Map<number, NowShowingRecord> = new Map();
      for (const m of nowShowing.Records.data) {
        movieMeta.set(m.movie_id, m);
        // chainMovieId = Empire's native numeric ID (stable, not title-based)
        const chainMovieId = String(m.movie_id);
        if (!movies.has(chainMovieId)) {
          // Prefer EN artwork, fall back to first available
          const artwork = m.altMovieContent?.find(c => c.lang_name === 'English')?.artwork
            ?? m.altMovieContent?.[0]?.artwork;

          movies.set(chainMovieId, {
            chainMovieId,
            title_en: m.movie_title.trim(),
            duration_min: m.mrrdr_runtime || undefined,
            exhibitor_rating: m.rating === 'TBC' ? undefined : m.rating,
            genre: m.genre_name || undefined,
            poster_url: artwork && artwork !== 'File Not Exist' ? artwork : undefined,
          });
        }
      }

      // Step 2: Get showtimes for each date
      for (const date of dates) {
        let sessions: SessionRecord[];
        try {
          const resp = await empireGet<{ Records: { data: SessionRecord[] } }>(
            `/api/cinema/admin/movie-confirmed-list-all?cinema_id=${cinema.externalId}&date=${date}&lang_id=1`, resolvedApiBase
          );
          sessions = resp.Records.data;
        } catch {
          continue; // no shows this date
        }

        for (const s of sessions) {
          if (s.ss_show_status !== 16) continue; // skip cancelled/inactive

          const chainMovieId = String(s.movie_id);

          // Add movie if we haven't seen it yet (might show up in future dates not in today's now-showing)
          if (!movies.has(chainMovieId)) {
            movies.set(chainMovieId, {
              chainMovieId,
              title_en: s.movie_title.trim(),
              duration_min: s.mrrdr_runtime || undefined,
            });
          }

          const showtime = `${s.ss_actual_start_date}T${s.ss_start_show_time}:00`;
          const stId = `${cinema.cinemaId}-${s.ss_id}`;

          if (!showtimeMap.has(stId)) {
            showtimeMap.set(stId, {
              id: stId,
              cinema_id: cinema.cinemaId,
              title_id: chainMovieId,
              showtime,
              screen_type: normalizeScreenType(s.screen_type_name, s.mf_name),
              language: s.lang_name?.toLowerCase() || undefined,
              subtitles: s.sub_lang_1_name?.toLowerCase() || undefined,
              // Empire Lebanon has no online booking configured
            });
          }
        }
      }
    } catch (err) {
      console.error(`Empire: failed scraping ${cinema.cinemaId}:`, err);
      errors.push(`${cinema.cinemaId}: ${err instanceof Error ? err.message : String(err)}`);
    }
  }

  if (errors.length === DEFAULT_CINEMAS.length) {
    throw new Error(`All Empire cinemas failed: ${errors.join('; ')}`);
  }

  return {
    chainId: 'empire-cinemas',
    titles: Array.from(movies.values()),
    showtimes: Array.from(showtimeMap.values()),
  };
}

// --- Helpers ---

async function empireGet<T>(path: string, base: string = API_BASE): Promise<T> {
  const resp = await fetchWithTimeout(`${base}${path}`, {
    headers: {
      Authorization: JWT,
      Accept: 'application/json',
      'User-Agent': 'Mozilla/5.0 (compatible; CultRoll/1.0)',
    },
  }, {
    resource: `Empire API ${path}`,
  });
  if (!resp.ok) throw new Error(`Empire API ${path} returned ${resp.status}`);
  return resp.json() as Promise<T>;
}

function normalizeScreenType(screenTypeName: string, formatName: string): string {
  const s = (screenTypeName + ' ' + formatName).toLowerCase();
  if (s.includes('imax')) return 'imax';
  if (s.includes('vip') || s.includes('premiere')) return 'vip';
  if (s.includes('3d')) return '3d';
  if (s.includes('dolby') || s.includes('atmos')) return 'dolby-atmos';
  return 'standard';
}
