/**
 * Taj Cinemas scraper (Jordan — Taj Mall, Amman)
 *
 * Tech: Laravel server-rendered HTML at tajcinemas.com
 * Strategy:
 *   1. Fetch homepage to discover current movie IDs
 *   2. For each movie, fetch /movies/{id} and parse date tabs + showtimes
 * Date tab structure: <a data-toggle="tab" href="#date-{paneId}"><span>Tue</span><br>03</a>
 * Showtime structure: <a href="/movies/{id}/book/{paneId}/{sessionId}">21:00</a>
 */

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

const BASE = 'https://www.tajcinemas.com';
const HEADERS = { 'User-Agent': 'Mozilla/5.0 (compatible; CultRoll/1.0)' };

interface TajOpts {
  baseUrl?: string;
  cinemaId?: string;
}

export async function scrapeTajCinemas(env: ScraperEnv, opts?: TajOpts): Promise<ScraperResult> {
  const resolvedBase = opts?.baseUrl ?? BASE;
  const resolvedCinemaId = opts?.cinemaId ?? 'taj-taj-mall';
  const movies: Map<string, ScrapedTitle> = new Map();
  const showtimes: ScrapedShowtime[] = [];

  // Step 1: get current movie IDs from homepage
  const movieIds = await getHomepageMovieIds(resolvedBase);

  // Step 2: fetch each movie page in parallel batches of 8
  for (let i = 0; i < movieIds.length; i += 8) {
    const batch = movieIds.slice(i, i + 8);
    const results = await Promise.allSettled(
      batch.map(id => fetchMoviePage(id, resolvedBase).then(parsed => ({ id, parsed })))
    );

    for (const result of results) {
      if (result.status !== 'fulfilled' || !result.value.parsed) continue;
      const { id: numericId, parsed } = result.value;
      // chainMovieId = Taj's native numeric page ID (stable, not title-based)
      const chainMovieId = String(numericId);

      if (!movies.has(chainMovieId)) {
        movies.set(chainMovieId, {
          chainMovieId,
          title_en: parsed.title,
          synopsis_en: parsed.synopsis,
          duration_min: parsed.duration,
          poster_url: parsed.posterUrl,
        });
      }

      for (const st of parsed.showtimes) {
        showtimes.push({
          id: `taj-mall-${chainMovieId}-${st.datetime.replace(/\D/g, '')}`,
          cinema_id: resolvedCinemaId,
          title_id: chainMovieId,
          showtime: st.datetime,
          screen_type: 'standard',
          booking_url: st.bookingUrl,
        });
      }
    }
  }

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

async function getHomepageMovieIds(baseUrl: string = BASE): Promise<number[]> {
  const resp = await fetchWithTimeout(baseUrl, { headers: HEADERS }, {
    resource: 'Taj homepage',
  });
  if (!resp.ok) return [];
  const html = await resp.text();
  const ids = new Set<number>();
  const re = /href="https?:\/\/www\.tajcinemas\.com\/movies\/(\d+)"/g;
  let m: RegExpExecArray | null;
  while ((m = re.exec(html)) !== null) ids.add(parseInt(m[1], 10));
  return Array.from(ids);
}

interface ParsedMovie {
  title: string;
  synopsis?: string;
  duration?: number;
  posterUrl?: string;
  showtimes: Array<{ datetime: string; bookingUrl?: string }>;
}

async function fetchMoviePage(id: number, baseUrl: string = BASE): Promise<ParsedMovie | null> {
  const resp = await fetchWithTimeout(`${baseUrl}/movies/${id}`, { headers: HEADERS }, {
    resource: `Taj movie ${id}`,
  });
  if (!resp.ok) return null;
  const html = await resp.text();
  if (html.length < 500) return null;

  // Title from <title> tag (format: "MOVIE NAME \n - Taj Cinemas")
  const titleM = html.match(/<title[^>]*>([^<\n-]+)/i);
  if (!titleM) return null;
  const title = stripHtml(titleM[1]).trim();
  if (!title || title.toLowerCase().includes('taj cinema')) return null;

  // Synopsis: <p> tag after keyword
  const synM = html.match(/SYNOPSIS[\s\S]{0,100}<p[^>]*>([\s\S]{20,500}?)<\/p>/i);
  const synopsis = synM ? stripHtml(synM[1]).trim() : undefined;

  // Duration: "136" in a <i> tag next to "Duration:"
  const durM = html.match(/Duration[^<]*<\/[^>]+>\s*<i[^>]*>(\d+)/i);
  const duration = durM ? parseInt(durM[1], 10) : undefined;

  // Poster: first /storage/ image
  const posterM = html.match(/src=["'](\/storage\/[^"']+\.(?:jpg|jpeg|png|webp))["']/i);
  const posterUrl = posterM ? `${baseUrl}${posterM[1]}` : undefined;

  // Parse date tabs: <a data-toggle="tab" href="#date-{paneId}"><span>Tue</span> <br> 03</a>
  const dateTabs = new Map<string, string>(); // paneId → ISO date
  const tabRe = /href="#date-(\d+)"><span>(\w+)<\/span>\s*<br>\s*(\d+)/g;
  let tabM: RegExpExecArray | null;
  while ((tabM = tabRe.exec(html)) !== null) {
    const paneId = tabM[1];
    const dayNum = parseInt(tabM[3], 10);
    const isoDate = dayNumToISODate(dayNum);
    dateTabs.set(paneId, isoDate);
  }

  // Parse showtimes: for each date pane, find booking links + times
  const movieShowtimes: Array<{ datetime: string; bookingUrl?: string }> = [];
  // Match each date-{paneId} section and extract times within it
  const paneRe = /id="date-(\d+)"[^>]*>([\s\S]*?)(?=id="date-\d+"|<\/div>\s*<\/div>\s*<\/div>\s*$)/g;
  let paneM: RegExpExecArray | null;
  while ((paneM = paneRe.exec(html)) !== null) {
    const paneId = paneM[1];
    const paneHtml = paneM[2];
    const isoDate = dateTabs.get(paneId);
    if (!isoDate) continue;

    // Find all booking links and their time text
    const linkRe = /href="(https?:\/\/www\.tajcinemas\.com\/movies\/\d+\/book\/\d+\/\d+)"[^>]*>\s*(\d{1,2}:\d{2})/g;
    let linkM: RegExpExecArray | null;
    while ((linkM = linkRe.exec(paneHtml)) !== null) {
      const bookingUrl = linkM[1];
      const timeStr = linkM[2];
      const datetime = `${isoDate}T${timeStr}:00`;
      movieShowtimes.push({ datetime, bookingUrl });
    }
  }

  // Fallback: if pane parsing failed, try global link search with date from tabs
  if (movieShowtimes.length === 0 && dateTabs.size > 0) {
    const firstDate = Array.from(dateTabs.values())[0];
    const linkRe = /href="(https?:\/\/www\.tajcinemas\.com\/movies\/\d+\/book\/(\d+)\/\d+)"[^>]*>\s*(\d{1,2}:\d{2})/g;
    let linkM: RegExpExecArray | null;
    while ((linkM = linkRe.exec(html)) !== null) {
      const bookingUrl = linkM[1];
      const paneId = linkM[2];
      const isoDate = dateTabs.get(paneId) ?? firstDate;
      const timeStr = linkM[3];
      movieShowtimes.push({ datetime: `${isoDate}T${timeStr}:00`, bookingUrl });
    }
  }

  return { title, synopsis, duration, posterUrl, showtimes: movieShowtimes };
}

/** Convert a day-of-month number to an ISO date string, using current/next month logic */
function dayNumToISODate(dayNum: number): string {
  const now = new Date();
  const today = now.getDate();
  const year = now.getFullYear();
  const month = now.getMonth(); // 0-based

  // If dayNum is >= today, use current month; otherwise next month
  if (dayNum >= today) {
    return `${year}-${(month + 1).toString().padStart(2, '0')}-${dayNum.toString().padStart(2, '0')}`;
  } else {
    const nextMonth = month + 1 === 12 ? 0 : month + 1;
    const nextYear = month + 1 === 12 ? year + 1 : year;
    return `${nextYear}-${(nextMonth + 1).toString().padStart(2, '0')}-${dayNum.toString().padStart(2, '0')}`;
  }
}
