"""
Playwright browser management for LinkedIn scraping.

This module provides async browser lifecycle management using linkedin_scraper v3's
BrowserManager. Implements a singleton pattern for browser reuse across tool calls
with session persistence via JSON files.
"""

import logging
from pathlib import Path

from linkedin_scraper import (
    AuthenticationError,
    BrowserManager,
    is_logged_in,
    login_with_cookie,
)
from linkedin_scraper.core import detect_rate_limit

from linkedin_mcp_server.config import get_config
from linkedin_mcp_server.utils import get_linkedin_cookie

logger = logging.getLogger(__name__)


# Default session file location
DEFAULT_SESSION_PATH = Path.home() / ".linkedin-mcp" / "session.json"

# Global browser instance (singleton)
_browser: BrowserManager | None = None
_headless: bool = True


def _apply_browser_settings(browser: BrowserManager) -> None:
    """Apply configuration settings to browser instance."""
    config = get_config()
    browser.page.set_default_timeout(config.browser.default_timeout)


async def get_or_create_browser(
    headless: bool | None = None,
    session_path: Path | None = None,
) -> BrowserManager:
    """
    Get existing browser or create and initialize a new one.

    Uses a singleton pattern to reuse the browser across tool calls.
    Loads session from file if available.

    Args:
        headless: Run browser in headless mode. Defaults to config value.
        session_path: Path to session file. Defaults to ~/.linkedin-mcp/session.json

    Returns:
        Initialized BrowserManager instance
    """
    global _browser, _headless

    if headless is not None:
        _headless = headless

    if session_path is None:
        session_path = DEFAULT_SESSION_PATH

    if _browser is not None:
        return _browser

    config = get_config()
    viewport = {
        "width": config.browser.viewport_width,
        "height": config.browser.viewport_height,
    }

    # Build launch options for custom browser path
    launch_options: dict[str, str] = {}
    if config.browser.chrome_path:
        launch_options["executable_path"] = config.browser.chrome_path
        logger.info("Using custom Chrome path: %s", config.browser.chrome_path)

    logger.info(
        "Creating new browser (headless=%s, slow_mo=%sms, viewport=%sx%s)",
        _headless,
        config.browser.slow_mo,
        viewport["width"],
        viewport["height"],
    )
    _browser = BrowserManager(
        headless=_headless,
        slow_mo=config.browser.slow_mo,
        user_agent=config.browser.user_agent,
        viewport=viewport,
        **launch_options,
    )
    await _browser.start()

    # Priority 1: Load session file if available
    if session_path.exists():
        try:
            await _browser.load_session(str(session_path))
            logger.info(f"Loaded session from {session_path}")
            # Navigate to LinkedIn to validate session
            await _browser.page.goto("https://www.linkedin.com/feed/")
            if await is_logged_in(_browser.page):
                _apply_browser_settings(_browser)
                return _browser
            logger.warning(
                "Session loaded but expired, trying to create session from cookie"
            )
        except Exception as e:
            logger.warning(f"Failed to load session: {e}")

    # Priority 2: Use cookie from environment
    if cookie := get_linkedin_cookie():
        try:
            await login_with_cookie(_browser.page, cookie)
            logger.info("Authenticated using LINKEDIN_COOKIE")
            _apply_browser_settings(_browser)
            return _browser
        except Exception as e:
            logger.warning(f"Cookie authentication failed: {e}")

    # No auth available - fail fast with clear error
    raise AuthenticationError(
        "No authentication found. Run with --get-session to create a session."
    )


async def close_browser() -> None:
    """Close the browser and cleanup resources."""
    global _browser

    if _browser is not None:
        logger.info("Closing browser...")
        await _browser.close()
        _browser = None
        logger.info("Browser closed")


def session_exists(session_path: Path | None = None) -> bool:
    """Check if a session file exists."""
    if session_path is None:
        session_path = DEFAULT_SESSION_PATH
    return session_path.exists()


def set_headless(headless: bool) -> None:
    """Set headless mode for future browser creation."""
    global _headless
    _headless = headless


async def validate_session() -> bool:
    """
    Check if the current session is still valid (logged in).

    Returns:
        True if session is valid and user is logged in
    """
    browser = await get_or_create_browser()
    return await is_logged_in(browser.page)


async def ensure_authenticated() -> None:
    """
    Validate session and raise if expired.

    Raises:
        AuthenticationError: If session is expired or invalid
    """
    if not await validate_session():
        raise AuthenticationError("Session expired or invalid.")


async def check_rate_limit() -> None:
    """
    Proactively check for rate limiting.

    Should be called after navigation to detect if LinkedIn is blocking requests.

    Raises:
        RateLimitError: If rate limiting is detected
    """
    browser = await get_or_create_browser()
    await detect_rate_limit(browser.page)


def reset_browser_for_testing() -> None:
    """Reset global browser state for test isolation."""
    global _browser, _headless
    _browser = None
    _headless = True
