/**
 * Mobile-side eporner.com resolver.
 *
 * eporner XHR zwraca gvideo.eporner.com mp4 URL-e podpisane krótkoterminowym tokenem
 * BOUND DO IP requestera (URL ma `<ts>_<ip>_<n>` w ścieżce — audit 2026-06-11 pokazał
 * `..._46.62.219.154_...` z VPS). Backend resolvuje z VPS → telefon dostaje URL bound
 * do IP VPS → direct 403 → fallback proxy → wideo przez Hetzner.
 *
 * Fix: telefon sam pobiera stronę + XHR (phone IP) → URL bound do telefonu → gra direct,
 * zero VPS. Port z app/extractors/tubes/eporner.py (vid+hash → /xhr/video → mp4 dict).
 */
import type { StreamLink } from '../types';

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';

const _VID_RE = /EP\.video\.player\.vid\s*=\s*'([^']+)'/;
const _HASH_RE = /EP\.video\.player\.hash\s*=\s*'([0-9a-fA-F]{32})'/;

/** True dla page_url eporner (origin tube:epornercom). */
export function isEpornerUrl(url: string | null | undefined): boolean {
  return !!url && /(?:^|\/\/|\.)eporner\.com\//i.test(url);
}

/** 32-hex hash → base36 w 4 chunkach po 8 hex (port _hash_to_b36). */
function hashToB36(hexHash: string): string {
  let out = '';
  for (const i of [0, 8, 16, 24]) {
    const n = parseInt(hexHash.slice(i, i + 8), 16);
    out += n.toString(36);
  }
  return out;
}

/**
 * Pobiera eporner stronę + XHR NA TELEFONIE → mp4 StreamLink-i (phone-IP-bound, grają
 * direct). Zwraca [] gdy brak (caller spada na backend). Mirror eporner.py.
 */
export async function resolveEpornerPage(pageUrl: string): Promise<StreamLink[]> {
  let html: string;
  try {
    const r = await fetch(pageUrl, { headers: { 'User-Agent': UA, Accept: 'text/html' } });
    if (!r.ok) return [];
    html = await r.text();
  } catch {
    return [];
  }
  const mVid = _VID_RE.exec(html);
  const mHash = _HASH_RE.exec(html);
  if (!mVid || !mHash) return [];
  const vid = mVid[1];
  const hashB36 = hashToB36(mHash[1]);
  const xhrUrl =
    `https://www.eporner.com/xhr/video/${vid}?hash=${hashB36}` +
    '&domain=www.eporner.com&pixelRatio=1&playerWidth=0&playerHeight=0' +
    '&fallback=false&embed=false&supportedFormats=mp4';
  let data: any;
  try {
    const r = await fetch(xhrUrl, {
      headers: {
        'User-Agent': UA,
        Referer: pageUrl,
        Accept: '*/*',
        'X-Requested-With': 'XMLHttpRequest',
      },
    });
    if (!r.ok) return [];
    data = await r.json();
  } catch {
    return [];
  }
  if (data && data.available === false) return [];
  const mp4 = (data && data.sources && data.sources.mp4) || {};
  const links: StreamLink[] = [];
  for (const [label, info] of Object.entries(mp4)) {
    const src = info && typeof info === 'object' ? (info as any).src : null;
    if (!src) continue;
    links.push({
      stream_url: src,
      direct_url: src,
      headers: { Referer: pageUrl, 'User-Agent': UA },
      quality: label,
      type: 'mp4',
    });
  }
  links.sort((a, b) => (parseInt(b.quality || '0', 10) || 0) - (parseInt(a.quality || '0', 10) || 0));
  return links;
}
