from contextlib import asynccontextmanager

from playwright.async_api import Browser, BrowserContext, Page, async_playwright

MOBILE_USER_AGENT = (
    "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) "
    "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
)

SAFARI_MIMICRY_SCRIPT = """
// Make Chromium look like real Safari to avoid detection
Object.defineProperty(navigator, 'vendor', {
    get: () => 'Apple Computer, Inc.'
});

Object.defineProperty(navigator, 'platform', {
    get: () => 'iPhone'
});

Object.defineProperty(navigator, 'maxTouchPoints', {
    get: () => 5
});

// Hide webdriver property
Object.defineProperty(navigator, 'webdriver', {
    get: () => false
});

// Remove chrome object
// eslint-disable-next-line no-undef
delete window.chrome;
"""


class MobilePlaywrightSession:
    """Mobile Playwright session manager for web scrapers."""

    def __init__(self, headless: bool = False, base_url: str | None = None):
        self.headless = headless
        self.base_url = base_url
        self.browser: Browser | None = None
        self.context: BrowserContext | None = None
        self.page: Page | None = None
        self._playwright = None

    async def __aenter__(self):
        await self.start()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.close()

    async def start(self):
        """Initialize a mobile-like Playwright session."""
        if self.browser:
            return

        self._playwright = await async_playwright().start()

        self.browser = await self._playwright.chromium.launch(
            headless=self.headless,
            slow_mo=300,  # Slow down for stability
        )

        self.context = await self.browser.new_context(
            user_agent=MOBILE_USER_AGENT,
            viewport={"width": 375, "height": 812},
            device_scale_factor=3,
            is_mobile=True,
            has_touch=True,
        )

        self.page = await self.context.new_page()
        await self.page.add_init_script(SAFARI_MIMICRY_SCRIPT)

    async def close(self):
        """Close browser and cleanup."""
        if self.browser:
            await self.browser.close()
            self.browser = None
            self.context = None
            self.page = None

        if self._playwright:
            await self._playwright.stop()
            self._playwright = None


@asynccontextmanager
async def mobile_playwright_session(headless: bool = False, base_url: str | None = None):
    """
    Context manager that yields (browser, context, page) with shared mobile settings applied.
    Uses MobilePlaywrightSession internally without requiring inheritance.
    """
    session = MobilePlaywrightSession(headless=headless, base_url=base_url)
    await session.start()
    try:
        yield session.browser, session.context, session.page
    finally:
        await session.close()


class PlaywrightSessionManager:
    """
    Manages Playwright session lifecycle for scrapers using composition.
    Provides a cleaner interface for scrapers to manage browser sessions.
    """

    def __init__(self, headless: bool = False, base_url: str | None = None):
        self.headless = headless
        self.base_url = base_url
        self._session_cm = None

    async def __aenter__(self):
        """Start the session and return browser, context, page tuple."""
        self._session_cm = mobile_playwright_session(self.headless, self.base_url)
        return await self._session_cm.__aenter__()

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """Clean up the session."""
        if self._session_cm:
            await self._session_cm.__aexit__(exc_type, exc_val, exc_tb)
            self._session_cm = None
