"""Mixdrop embed hoster — P.A.C.K.E.R. eval → MDCore.wurl direct mp4.

Pattern (verified 2026-05-15 via curl_cffi impersonate=chrome120):
  1. Fetch `https://mixdrop.my/e/<id>` → 200 z 95KB body, redirect 301 do
     `https://m1xdrop.bz/e/<id>` (current TLD).
  2. Body zawiera P.A.C.K.E.R. obfuscated JS block:
     `eval(function(p,a,c,k,e,d){...}('...packed...',N,N,'...|...'.split('|'),0,{}))`
  3. yt-dlp's `decode_packed_codes()` rozkrywa do ~390 chars JavaScript:
     `MDCore.wurl="//a-delivery22.mxcontent.net/v2/<id>.mp4?s=<sig>&e=<exp>&_t=<ts>"`
  4. URL na `mxcontent.net` zwraca **direct mp4** (Content-Type: video/mp4,
     Content-Length: ~485MB) — działa z Hetzner VPS IP, brak token IP-bind.

`s` to signed token (HMAC?), `e` to expiry timestamp (unix sec), `_t` to
issued timestamp. Token jest valid ~24h od `_t`. Refetching embed page po
expiry zwraca nowy URL.

Active mango movies: 203 playbacks origin='mangoporn:mixdrop' w DB.
"""
from __future__ import annotations

import logging
import re

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

log = logging.getLogger(__name__)


_PACKER_RE = re.compile(
    r"eval\(function\(p,a,c,k,e,d\)\{.+?\}\(.+?\)\)",
    re.DOTALL,
)
_MP4_URL_RE = re.compile(r'MDCore\.wurl\s*=\s*"([^"]+\.mp4[^"]*)"')
# Dead-video page (200 OK but no packer, only the "sorry" shell). Wcześniej nasz
# extractor zwracał None bez sygnału "dead" → playback.py nie ustawiał dead_at,
# mobile dostawał pusty wynik → czarny ekran zamiast skip-to-next-source.
_DEAD_RE = re.compile(
    r"can't find the video|WE ARE SORRY",
    re.IGNORECASE,
)


def extract(page_url: str, *, timeout: float = 30.0) -> list[StreamSource] | None:
    # UA + Accept są wymagane — bez nich mixdrop dla VALID video zwraca minimalny
    # body bez P.A.C.K.E.R. (sam stream_proxy._refetch_mixdrop_url też tak robi).
    # Brak headerów powodował że extract() na żywym mixdrop ID dostawał shell bez
    # packera → no match → None → mobile dostawał czarny ekran.
    headers = {
        "User-Agent": _DEFAULT_UA,
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    }
    res = browser_get(page_url, headers=headers, timeout=timeout)
    if res.status_code != 200 or not res.text:
        log.info("mixdrop: fetch fail status=%s url=%s", res.status_code, page_url)
        return None

    m = _PACKER_RE.search(res.text)
    if not m:
        if _DEAD_RE.search(res.text):
            raise HosterDead(f"mixdrop {page_url}: video not found")
        log.info("mixdrop: no P.A.C.K.E.R. block in %s (page changed?)", page_url)
        return None

    try:
        from yt_dlp.utils import decode_packed_codes
        decoded = decode_packed_codes(m.group(0))
    except Exception as e:
        log.warning("mixdrop: decode_packed_codes failed: %s", e)
        return None

    url_match = _MP4_URL_RE.search(decoded)
    if not url_match:
        log.info("mixdrop: no MDCore.wurl in decoded payload (len=%d)", len(decoded))
        return None

    raw_url = url_match.group(1)
    # URL z mixdrop często jest protocol-relative (`//a-delivery22...`).
    if raw_url.startswith("//"):
        raw_url = "https:" + raw_url

    return [
        StreamSource(
            link=raw_url,
            quality=None,  # mixdrop nie listuje quality variants w MDCore
            type="mp4",
            referer="https://mixdrop.my/",
            # mxcontent CDN wymaga **same-session cookies** z embed page +
            # Chrome JA3. Backend `extract` zamyka sesję po fetch → mobile
            # próbuje mp4 bez cookies → 403. Proxy MUSI re-fetchować embed
            # w fresh curl_cffi session, extract nowy mp4 URL, stream.
            # `refetch_url` w raw → token field `rf` → proxy refresh logic.
            raw={
                "proxy_impersonate": True,
                "refetch_url": page_url,  # embed page do re-extract
                "refetch_hoster": "mixdrop",
            },
        )
    ]
