from __future__ import annotations

import logging
from typing import Optional, Tuple

from playwright.async_api import (
    async_playwright,
    Page,
    Browser,
    BrowserContext,
    Playwright,
)

# 新增 stealth 导入
from playwright_stealth import Stealth

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

logger = logging.getLogger("loki")


class TikTok(RequestMixin):
    PLATFORM = "TikTok"

    def __init__(
            self,
            *,
            profile: Profile,
            auto_load_cookies: bool = True,
    ) -> None:
        super().__init__(profile=profile, auto_load_cookies=auto_load_cookies)
        self._base = "https://www.tiktok.com"

        # 这些在 async create() 里初始化
        self._playwright: Optional[Playwright] = None
        self._browser: Optional[Browser] = None

    @classmethod
    async def create(
            cls,
            *,
            profile: Profile | None = None,
            profile_name: str = "default",
            profile_manager: ProfileManager | None = None,
            auto_load_cookies: bool = True,
            headless: bool = True,
    ) -> "TikTok":
        """
        异步工厂：负责解决 __init__ 里不能 await 的问题。
        """
        if profile is None:
            manager = profile_manager or ProfileManager()
            profile = manager.get(cls.PLATFORM, profile_name)

        self = cls(profile=profile, auto_load_cookies=auto_load_cookies)

        # 加强 launch 参数（针对 TikTok 指纹检测）
        self._playwright = await async_playwright().start()
        self._browser = await self._playwright.chromium.launch(
            headless=headless,
            args=[
                "--disable-blink-features=AutomationControlled",
                "--no-sandbox",
                "--disable-setuid-sandbox",
                "--disable-dev-shm-usage",
                "--disable-infobars",
                "--window-size=1280,800",
                "--start-maximized",
                "--disable-background-timer-throttling",
                "--disable-renderer-backgrounding",
            ],
        )
        return self

    async def close(self) -> None:
        """
        关闭浏览器与 Playwright。适合在 finally 里调用。
        """
        try:
            if self._browser is not None:
                await self._browser.close()
        finally:
            if self._playwright is not None:
                await self._playwright.stop()

        self._browser = None
        self._playwright = None

    async def _new_page(self) -> Tuple[Optional[BrowserContext], Optional[Page]]:
        """
        新建 context + page。失败会清理 context，返回 (None, None)。
        """
        if self._browser is None:
            logger.error("Browser 未初始化：请先使用 await TikTok.create()")
            return None, None

        context: Optional[BrowserContext] = None
        try:
            context = await self._browser.new_context(
                viewport={"width": 1280, "height": 800},
                # 更新 UA 到较新版本（匹配 2026 年常见浏览器）
                user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
                locale="zh-CN",
                timezone_id="Asia/Shanghai",
                # 加强 headers，伪装 Windows 平台（TikTok 很敏感）
                extra_http_headers={
                    "sec-ch-ua": '"Chromium";v="128", "Not;A=Brand";v="99", "Google Chrome";v="128"',
                    "sec-ch-ua-mobile": "?0",
                    "sec-ch-ua-platform": '"Windows"',
                    "sec-ch-ua-platform-version": '"10.0.0"',
                    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
                },
            )

            # 关键：应用 stealth 到 context（所有 page 自动生效）
            stealth = Stealth()  # 默认配置已覆盖大部分 evasions
            await stealth.apply_stealth_async(context)
            logger.debug("已应用 playwright-stealth 到 TikTok context")

            if self.profile:
                cookies = self.profile.build_playwright_cookies(base_url=self._base)
                if cookies:
                    await context.add_cookies(cookies)

            page = await context.new_page()
            return context, page
        except Exception:
            logger.exception("创建页面失败")
            if context is not None:
                await context.close()
            return None, None

    async def get_profile_data(self, username: str) -> dict | None:
        profile_url = f"{self._base}/@{username}"

        context, page = await self._new_page()
        if page is None or context is None:
            return None

        try:
            # 等待 item_list 接口响应（TikTok 常用这个 feed 接口）
            async with page.expect_response(
                    lambda r: ("api/post/item_list" in r.url)
                              and (r.request.resource_type in ("xhr", "fetch"))
                              and (r.status == 200),
                    timeout=45_000,  # 适当加长，TikTok 有时加载慢
            ) as resp_info:
                # 先访问首页预热（生成 device_id、msToken 等指纹）
                await page.goto(self._base, wait_until="domcontentloaded", timeout=30_000)
                await page.wait_for_timeout(3000)  # 给 3 秒让 session 稳定

                # 再访问目标 profile
                await page.goto(profile_url, wait_until="domcontentloaded", timeout=30_000)
                # 可选：模拟滚动加载更多（如果需要多页数据）
                # await page.evaluate("window.scrollBy(0, 1000)")
                # await page.wait_for_timeout(2000)

            resp = await resp_info.value
            data = await resp.json()
            return data

        except Exception:
            logger.exception("抓取 profile 接口失败: %s", profile_url)
            return None
        finally:
            await context.close()