"""
Playwright browser session manager.

Priority order:
  1. CDP (remote debugging) — attaches to your already-running Chrome on port 9222.
     Launch Chrome with: chrome.exe --remote-debugging-port=9222
     Sessions are your real Chrome sessions — zero re-login needed.

  2. Persistent profile at ~/.chorus/profile/ — a dedicated Chrome window with
     saved sessions.  Log in once; sessions persist across Chorus restarts.

If the browser context dies mid-session (user closes Chrome, CDP drops, etc.),
get_page() automatically reconnects before returning the page.
"""
import asyncio
import aiohttp
from pathlib import Path
from playwright.async_api import async_playwright, BrowserContext, Page

PROFILE_DIR = Path.home() / ".chorus" / "profile"
CDP_URL = "http://localhost:9222"


async def _cdp_available() -> bool:
    """Return True if Chrome remote debugging is reachable on port 9222."""
    try:
        async with aiohttp.ClientSession() as s:
            async with s.get(f"{CDP_URL}/json/version", timeout=aiohttp.ClientTimeout(total=1.5)) as r:
                return r.status == 200
    except Exception:
        return False


class BrowserManager:
    def __init__(self):
        self._playwright = None
        self._ctx: BrowserContext | None = None
        self._browser = None        # only set when using CDP
        self._pages: dict[str, Page] = {}
        self._using_cdp = False
        self._start_lock = asyncio.Lock()

    @property
    def playwright(self):
        return self._playwright

    async def start(self):
        self._playwright = await async_playwright().start()
        await self._connect()

    async def _connect(self):
        """Establish browser context. Called on startup and on reconnect."""
        # ── 1. Try CDP (existing Chrome with --remote-debugging-port=9222) ──
        if await _cdp_available():
            try:
                self._browser = await self._playwright.chromium.connect_over_cdp(CDP_URL)
                contexts = self._browser.contexts
                self._ctx = contexts[0] if contexts else await self._browser.new_context()
                self._using_cdp = True
                print("[Chorus] Connected to existing Chrome via CDP — using your real sessions.")
                return
            except Exception as e:
                print(f"[Chorus] CDP available but connect failed ({e}), falling back to profile.")

        # ── 2. Persistent shared profile ──────────────────────────────────
        self._using_cdp = False
        self._browser = None
        PROFILE_DIR.mkdir(parents=True, exist_ok=True)
        launch_args = dict(
            user_data_dir=str(PROFILE_DIR),
            headless=False,
            args=["--disable-blink-features=AutomationControlled"],
            viewport={"width": 1280, "height": 800},
        )
        try:
            self._ctx = await self._playwright.chromium.launch_persistent_context(
                channel="chrome", **launch_args
            )
        except Exception:
            self._ctx = await self._playwright.chromium.launch_persistent_context(
                **launch_args
            )

    async def _ensure_context(self):
        """If the browser context has been closed, reconnect transparently."""
        needs_reconnect = False
        if self._ctx is None:
            needs_reconnect = True
        else:
            try:
                # Accessing .pages raises if the context is closed
                _ = self._ctx.pages
            except Exception:
                needs_reconnect = True

        if needs_reconnect:
            async with self._start_lock:
                # Double-check after acquiring lock
                try:
                    if self._ctx is not None:
                        _ = self._ctx.pages
                        return  # another coroutine already reconnected
                except Exception:
                    pass
                print("[Chorus] Browser context lost — reconnecting…")
                self._pages.clear()
                self._ctx = None
                try:
                    await self._connect()
                    print("[Chorus] Reconnected.")
                except Exception as e:
                    raise RuntimeError(f"Could not reconnect to browser: {e}")

    async def stop(self):
        if self._using_cdp:
            if self._browser:
                await self._browser.disconnect()
        else:
            if self._ctx:
                await self._ctx.close()
        if self._playwright:
            await self._playwright.stop()

    async def get_context(self, platform: str = "default", profile: str = "default") -> BrowserContext:
        await self._ensure_context()
        return self._ctx

    async def get_page(self, platform: str, profile: str = "default") -> Page:
        await self._ensure_context()
        key = f"{platform}:{profile}"
        page = self._pages.get(key)
        if page is None or page.is_closed():
            page = await self._ctx.new_page()
            self._pages[key] = page
        return page

    def list_profiles(self, platform: str) -> list[str]:
        return ["default"]


# Singleton
manager = BrowserManager()
