"""BrowserManager — Playwright lifecycle management.

Handles launching the browser, creating contexts/pages, and tearing down
cleanly.  Driven by the BrowserConfig from antiqa.json.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Any

from playwright.sync_api import Browser, BrowserContext, Page, Playwright, sync_playwright

from antiqa.config.schema import BrowserConfig

log = logging.getLogger("antiqa.browser")

_LAUNCHER_MAP = {
    "chromium": "chromium",
    "firefox": "firefox",
    "webkit": "webkit",
}


class BrowserManager:
    """Owns the Playwright instance, browser, context, and active page."""

    def __init__(self, config: BrowserConfig, logs_dir: str = "logs/") -> None:
        self.config = config
        self.logs_dir = Path(logs_dir)
        self.logs_dir.mkdir(parents=True, exist_ok=True)

        self._pw: Playwright | None = None
        self._browser: Browser | None = None
        self._context: BrowserContext | None = None
        self._page: Page | None = None
        self._recording: bool = False

    # ── Properties ─────────────────────────────────────

    @property
    def page(self) -> Page:
        if self._page is None:
            raise RuntimeError("Browser not launched. Call launch() first.")
        return self._page

    @property
    def context(self) -> BrowserContext:
        if self._context is None:
            raise RuntimeError("Browser not launched. Call launch() first.")
        return self._context

    @property
    def browser(self) -> Browser:
        if self._browser is None:
            raise RuntimeError("Browser not launched. Call launch() first.")
        return self._browser

    # ── Lifecycle ──────────────────────────────────────

    def launch(
        self,
        record_video: bool = False,
        storage_state: str | Path | None = None,
    ) -> Page:
        """Start Playwright, launch browser, create context and page.

        Args:
            record_video: If True, record a video of the session.
            storage_state: Path to a previously saved storage state JSON
                           (cookies + localStorage) to restore.
        """
        log.info(
            "Launching %s (headless=%s)", self.config.type, self.config.headless,
        )

        self._pw = sync_playwright().start()

        engine = _LAUNCHER_MAP.get(self.config.type, "chromium")
        launcher = getattr(self._pw, engine)
        self._browser = launcher.launch(headless=self.config.headless)

        ctx_kwargs: dict[str, Any] = {
            "viewport": {"width": 1280, "height": 720},
        }
        if record_video:
            video_dir = self.logs_dir / "videos"
            video_dir.mkdir(parents=True, exist_ok=True)
            ctx_kwargs["record_video_dir"] = str(video_dir)
            ctx_kwargs["record_video_size"] = {"width": 1280, "height": 720}
            self._recording = True

        if storage_state:
            path = Path(storage_state)
            if path.is_file():
                ctx_kwargs["storage_state"] = str(path)
                log.info("Restoring session from %s", path)

        self._context = self._browser.new_context(**ctx_kwargs)
        self._page = self._context.new_page()
        log.info("Browser ready")
        return self._page

    def new_page(self) -> Page:
        """Open a new tab in the current context."""
        self._page = self.context.new_page()
        return self._page

    def close(self) -> None:
        """Tear down page, context, browser, and Playwright."""
        if self._context:
            try:
                self._context.close()
            except Exception:
                pass
        if self._browser:
            try:
                self._browser.close()
            except Exception:
                pass
        if self._pw:
            try:
                self._pw.stop()
            except Exception:
                pass

        self._page = None
        self._context = None
        self._browser = None
        self._pw = None
        log.info("Browser closed")

    # ── Context manager ────────────────────────────────

    def __enter__(self) -> "BrowserManager":
        self.launch()
        return self

    def __exit__(self, *_: object) -> None:
        self.close()
