from __future__ import annotations

import re
import time
from typing import List, Dict
import logging
from bs4 import BeautifulSoup, Tag
from playwright.sync_api import sync_playwright
from urllib.parse import urlencode

from loki.common.profile import Profile, ProfileManager
from loki.scrapers.base import Method, RequestMixin

logger = logging.getLogger('loki')

_CODE_CMP_RE = re.compile(r"([A-Z]{2,10})[-_ ]*(\d{2,6})", re.I)

class JavDB(RequestMixin):
    PLATFORM = "JavDB"

    def __init__(
        self,
        *,
        profile: Profile | None = None,
        profile_name: str = "default",
        profile_manager: ProfileManager | None = None,
        auto_load_cookies: bool = True,
    ) -> None:
        if profile is None:
            manager = profile_manager or ProfileManager()
            profile = manager.get(self.PLATFORM, profile_name)

        super().__init__(profile=profile, auto_load_cookies=auto_load_cookies)
        self._base = 'https://javdb.com'
        self._playwright = sync_playwright().start()
        self._browser = self._playwright.chromium.launch(
            headless=True,
            args=[
                "--disable-blink-features=AutomationControlled",
                "--start-maximized"
            ]
        )
        
    def _get_soup(self, url: str, params: Dict = {}) -> BeautifulSoup | None:
        try:
            context = self._browser.new_context(
                viewport={"width": 1280, "height": 800},
                user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36",
                locale="zh-CN",
                timezone_id="Asia/Shanghai"
            )
            page = context.new_page()
            try:
                page.goto(f'{url}?{urlencode(params)}', wait_until="domcontentloaded", timeout=10000)
                return BeautifulSoup(page.content(), 'html.parser')
            finally:
                context.close()  # 关键：每次用完关 context
        except Exception:
            logger.exception("请求异常 %s", url)
        return None   
    
    def close(self):
        self._browser.close()
        self._playwright.stop()
        
    def _norm_code(self, s: str | None) -> str | None:
        if not s:
            return None
        s = str(s).upper().replace('.', '-').replace('_', '-').replace(' ', '-')
        m = _CODE_CMP_RE.search(s)
        if not m:
            return None
        prefix = m.group(1).upper()
        digits = (m.group(2) or '').lstrip('0') or '0'
        return f"{prefix}-{digits}"
    
    def _abs_url(self, href: str | None) -> str:
        h = (href or "").strip()
        if not h:
            return ""
        if h.startswith("http://") or h.startswith("https://"):
            return h
        if not h.startswith("/"):
            h = "/" + h
        return self._base + h
    
    def search(self, code: str, has_magnet: bool = True, no_subtitle: bool=True, no_uncensored: bool=True) -> Dict:
        search_code = self._norm_code(code) or code
        result = {
            'code': search_code
        }
        
        url = f'https://javdb.com/search'
        params = {
            'q': search_code,
            'f': 'all'
        }
        if has_magnet:
            params['f'] = 'download'
            
        soup = self._get_soup(url, params=params)
        if not soup:
            return result
        
        target_url = ''
        items = soup.select(".movie-list .item")
        for it in items:
            title_el = it.select_one("a .video-title strong")
            link_el = it.select_one("a[href]")
            if not title_el or not link_el:
                continue
            found_text = title_el.get_text(strip=True)
            found_norm = self._norm_code(found_text)
            # 只比较“前缀-数字”，忽略数字后的 A/B/CH 等
            if found_norm and found_norm == search_code:
                href = link_el.get("href", "")
                if isinstance(href, str):
                    target_url = self._abs_url(href.strip())
                    break
        
        if target_url:
            soup = self._get_soup(target_url)
            if not soup:
                return result
            
            actress_a = soup.select_one('.movie-panel-info a:has(+ .female)')
            if isinstance(actress_a, Tag):
                result['actress_name'] = actress_a.text
            
            items = soup.select("#magnets-content .item")
            best_magnet = ''
            best_size_gib = -1.0
        
            def size_from_meta(txt: str) -> float:
                # 如 "10.44GB, 1個文件" / "700MB, 2 files"
                s = txt.upper()
                m = re.search(r"([0-9]+(?:\.[0-9]+)?)\s*(GB|G|MB|M)", s)
                if not m:
                    return 0.0
                val = float(m.group(1))
                unit = m.group(2)
                if unit.startswith("G"):
                    return val
                return val / 1024.0
        
            for it in items:
                a = it.select_one("a[href^='magnet:']")
                name_el = it.select_one('span.name')
                if isinstance(name_el, Tag):
                    if no_uncensored and ('-uc' in name_el.text.lower() or '无码' in name_el.text.lower() or '-u.' in name_el.text.lower()):
                        continue
                    if no_subtitle and '字幕' in name_el.text.lower():
                        continue
                
                has_subtitle = False
                tags_el = it.select('.tags span')
                for tag_el in tags_el:
                    if isinstance(tag_el, Tag):
                        if '字幕' in tag_el.text.strip():
                            has_subtitle = True
                            break
                if no_subtitle and has_subtitle:
                    continue
                
                meta_el = it.select_one(".meta")
                if not a or not meta_el:
                    continue
                href_str = a.get("href", "")
                if isinstance(href_str, str):
                    magnet = href_str.strip()
                meta = meta_el.get_text(strip=True)
                sz = size_from_meta(meta)
                if sz > best_size_gib:
                    best_size_gib = sz
                    best_magnet = str(magnet)
        
            # 尝试在评论区找
            if not best_magnet:
                review_html = self._get_soup(f"{target_url}/reviews/lastest")
                if review_html:
                    for content in review_html.select(".review-items .review-item .content"):
                        if content:
                            if 'magnet:' in content.get_text():
                                match = re.search(r"(magnet:\?xt=urn:[a-z0-9]+:[a-zA-Z0-9]{32,})", content.get_text())
                                if match:
                                    best_magnet = str(match.group(1))
                                    break
                            elif 'ed2k:' in content.get_text():
                                match = re.search(r"(ed2k://\|file\|[^ ]+)", content.get_text())
                                if match:
                                    best_magnet = str(match.group(1))
                                    break
        
            result['magnet'] = best_magnet
        
        return result
        
        