"""eporner.com — direct stream extractor.

Page → wyciągnij `EP.video.player.vid` + `EP.video.player.hash` → XHR
`/xhr/video/<vid>?hash=<base36>` → JSON z multi-quality mp4 URL'ami (240p–1080p).

Bez hasha gvideo.eporner.com URL'e zwracają 403 (są podpisane krótkoterminowymi
tokenami które XHR zwraca świeże). Algorytm hex→base36 ekwiwalentny temu z
aplikacji AIO Streamer (`rf1.java`):
  BigInteger(hex[0:8],16).toString(36) + BigInteger(hex[8:16],16).toString(36)
  + BigInteger(hex[16:24],16).toString(36) + BigInteger(hex[24:32],16).toString(36)

URL-e są bound do IP requestera (więc resolver musi pobiegać z VPS-a, nie z
klienta) i ważne ~kilka godzin.
"""
from __future__ import annotations

import json
import logging
import re

from app.extractors._fetch import _DEFAULT_UA, browser_get, fetch_tube_html
from app.extractors._models import StreamSource

log = logging.getLogger(__name__)


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


def _hash_to_b36(hex_hash: str) -> str:
    """Konwertuje 32-znakowy hex hash na base36 w 4 chunkach po 8 znaków."""
    parts = []
    for i in (0, 8, 16, 24):
        n = int(hex_hash[i : i + 8], 16)
        if n == 0:
            parts.append("0")
            continue
        s = ""
        while n > 0:
            d = n % 36
            ch = chr(ord("0") + d) if d < 10 else chr(ord("a") + d - 10)
            s = ch + s
            n //= 36
        parts.append(s)
    return "".join(parts)


def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
    html = fetch_tube_html(page_url, timeout=timeout)
    m_vid = _VID_RE.search(html)
    m_hash = _HASH_RE.search(html)
    if not m_vid or not m_hash:
        log.warning("eporner: no vid/hash in %s", page_url)
        return None
    vid = m_vid.group(1)
    hash_b36 = _hash_to_b36(m_hash.group(1))
    xhr_url = (
        f"https://www.eporner.com/xhr/video/{vid}?hash={hash_b36}"
        "&domain=www.eporner.com&pixelRatio=1&playerWidth=0&playerHeight=0"
        "&fallback=false&embed=false&supportedFormats=mp4"
    )
    headers = {
        "User-Agent": _DEFAULT_UA,
        "Referer": page_url,
        "Accept": "*/*",
        "X-Requested-With": "XMLHttpRequest",
    }
    try:
        r = browser_get(xhr_url, headers=headers, timeout=timeout, follow_redirects=True)
        r.raise_for_status()
        data = json.loads(r.text)
    except Exception as e:
        log.warning("eporner xhr fetch %s failed: %s", xhr_url, e)
        return None

    if not data.get("available", True):
        log.info("eporner xhr %s: available=false", vid)
        return None

    mp4_dict = (data.get("sources") or {}).get("mp4") or {}
    sources: list[StreamSource] = []
    for label, info in mp4_dict.items():
        if not isinstance(info, dict):
            continue
        src = info.get("src")
        if not src:
            continue
        sources.append(StreamSource(link=src, quality=label, type="mp4"))

    if not sources:
        log.warning("eporner xhr %s: no mp4 sources in JSON", vid)
        return None
    return sources
