/**
 * Mobile-side get_file → final CDN resolver.
 *
 * Tuby typu hdporn.gg / fullmovies.xxx serwują `<source>` = `.../get_file/...mp4`,
 * które 302-redirectuje na fpvcdn.com z IP FETCHERA wbitym w URL (`ip=<kto-pobrał>`).
 * Backend NIE może tego zresolwować (związałby fpvcdn z IP VPS → telefon 403), więc
 * oddaje get_file URL niezresolwowany. Ale ExoPlayer wywala się na tym cross-domain
 * redirekcie (gubi Referer / nie domyka) → fallback na proxy → „mignięcie".
 *
 * Fix: resolvujemy redirect TU, w JS na telefonie (fpvcdn bindje się do IP telefonu),
 * i podajemy ExoPlayerowi finalny CDN URL — bez redirectu, bez błędu, bez migotania,
 * bez proxy. Ten sam wzorzec co doodstream.ts (`redirect: 'manual'` + Location header,
 * potwierdzone że działa na Android RN).
 */
const UA =
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36';

/** get_file URL który wymaga in-session resolve (nie nasz proxy URL). */
export function isGetFileUrl(url: string): boolean {
  return /\/get_file\//.test(url) && !/\/proxy\//.test(url);
}

const _SOURCE_RE = /<source\s+src=['"]([^'"]+\/get_file\/[^'"]+\.mp4[^'"]*)['"][^>]*?(?:title|label)=['"]?([^'">]*)/gi;
const _SKIP_Q = /2160|1440|4k/i;

/**
 * Pełny resolve dla hdporn.gg/fullmovies.xxx OD STRONY (nie od get_file URL).
 *
 * KLUCZOWE (z logów urządzenia 2026-06-06): get_file jest zbindowany do IP tego kto
 * załadował STRONĘ. Backend (VPS) ładuje stronę → get_file dla IP VPS → telefon fetchuje
 * → 410. Dlatego telefon musi sam załadować stronę (phone IP) → dostać phone-bound
 * get_file → follow 302 → fpvcdn z IP telefonu → ExoPlayer gra. Pomija 4K (martwe na fpvcdn).
 *
 * `quality` = preferowana etykieta z backendu (np. "720p"); fallback = pierwszy nie-4K.
 * Zwraca finalny CDN URL lub null (caller wtedy gra oryginał = proxy fallback).
 */
export async function resolveGetFilePage(
  pageUrl: string,
  quality?: string | null,
  referer?: string,
): Promise<string | null> {
  let html: string;
  try {
    const r = await fetch(pageUrl, { headers: { 'User-Agent': UA, Accept: 'text/html' } });
    if (!r.ok) return null;
    html = await r.text();
  } catch {
    return null;
  }
  const wantQ = (quality || '').replace(/\s+/g, '').toLowerCase();
  let pick: string | null = null;
  let m: RegExpExecArray | null;
  _SOURCE_RE.lastIndex = 0;
  while ((m = _SOURCE_RE.exec(html)) !== null) {
    const q = (m[2] || '').trim();
    if (_SKIP_Q.test(q)) continue;
    let u = m[1];
    if (u.startsWith('//')) u = 'https:' + u;
    if (wantQ && q && q.replace(/\s+/g, '').toLowerCase() === wantQ) {
      pick = u;
      break; // dokładne dopasowanie jakości
    }
    if (!pick) pick = u; // pierwszy nie-4K jako fallback
  }
  if (!pick) return null;
  const ref = referer || (() => {
    try {
      return new URL(pageUrl).origin + '/';
    } catch {
      return undefined;
    }
  })();
  return resolveGetFile(pick, ref);
}

/**
 * Follow get_file 302 → finalny CDN URL (z IP telefonu). Zwraca finalny URL gdy
 * dojdzie do nie-get_file Location, oryginalny URL gdy get_file serwuje direct (2xx),
 * lub null przy błędzie (caller wtedy gra oryginał = obecne zachowanie z fallbackiem).
 */
export async function resolveGetFile(url: string, referer?: string): Promise<string | null> {
  let cur = url;
  for (let hop = 0; hop < 4; hop++) {
    let r: Response;
    try {
      r = await fetch(cur, {
        method: 'GET',
        redirect: 'manual',
        headers: {
          'User-Agent': UA,
          Range: 'bytes=0-1',
          ...(referer ? { Referer: referer } : {}),
        },
      });
    } catch {
      return null;
    }
    const loc = r.headers.get('location');
    if (r.status >= 300 && r.status < 400) {
      if (!loc) return null;
      try {
        cur = new URL(loc, cur).toString();
      } catch {
        return null;
      }
      if (!isGetFileUrl(cur)) return cur; // dotarliśmy do finalnego CDN
      continue; // kolejny get_file hop (rzadkie)
    }
    if (r.status >= 200 && r.status < 300) {
      return cur; // get_file serwuje direct, bez redirectu — grywalne
    }
    // status 0 / opaqueredirect (RN okhttp czasem dla redirect:'manual') albo 4xx/5xx —
    // nie da się odczytać celu, caller zagra oryginał (proxy fallback).
    return null;
  }
  return cur;
}
