from __future__ import annotations

import logging
from typing import Optional, Tuple

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

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)

        # 正确的 async 启动方式
        self._playwright = await async_playwright().start()
        self._browser = await self._playwright.chromium.launch(
            headless=headless,
            args=[
                "--disable-blink-features=AutomationControlled",
            ],
        )
        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},
                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 = 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:
            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=30_000,
            ) as resp_info:
                await page.goto(profile_url, wait_until="domcontentloaded", timeout=30_000)

            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()
