"""Fixtures for Playwright frontend E2E tests.

Architecture:
- Each test gets an isolated temp SQLite DB.
- A FastAPI uvicorn server runs on a random port in a background thread.
- CANTEEN_SKIP_AUTH=1 skips auth middleware so Playwright doesn't need real tokens.
- Playwright launches system Google Chrome (Ubuntu 26.04 can't install bundled browsers,
  and Chrome 148 SIGTRAPs with certain --disable-features flags; ignore_default_args
  workaround applied).
- Viewport: iPhone 14 (390x844), Geolocation: Orlando, FL.
"""

# Chrome 148 on Ubuntu 26.04 (kernel 7.0) SIGTRAPs when Playwright's default
# --disable-features and related flags are passed. Ignoring these defaults
# allows Chrome to launch cleanly with DevTools protocol.
CHROME_IGNORE_DEFAULTS = [
    '--disable-field-trial-config',
    '--disable-background-networking',
    '--disable-background-timer-throttling',
    '--disable-breakpad',
    '--disable-client-side-phishing-detection',
    '--disable-default-apps',
    '--disable-dev-shm-usage',
    '--disable-extensions',
    '--disable-hang-monitor',
    '--disable-ipc-flooding-protection',
    '--disable-popup-blocking',
    '--disable-prompt-on-repost',
    '--disable-renderer-backgrounding',
    '--disable-sync',
    '--enable-automation',
]

import importlib
import os
import socket
import sys
import tempfile
import threading
import time
from pathlib import Path

import pytest
import uvicorn
from playwright.sync_api import sync_playwright

# Ensure project root is on path
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

# Global env: skip auth for all tests
os.environ["CANTEEN_SKIP_AUTH"] = "1"

# ── device profiles ─────────────────────────────────────────────────────────
# Set CANTEEN_DEVICE=pixel_9a in env to run tests with Pixel 9a viewport.
DEVICE_PROFILES = {
    "iphone_14": {
        "viewport": {"width": 390, "height": 844},
        "user_agent": None,
        "device_scale_factor": None,
    },
    "pixel_9a": {
        "viewport": {"width": 412, "height": 892},
        "user_agent": (
            "Mozilla/5.0 (Linux; Android 15; Pixel 9a) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/130.0.6723.58 Mobile Safari/537.36"
        ),
        "device_scale_factor": 2.625,
    },
}


def get_device_config() -> tuple:
    """Return device config dict + name based on CANTEEN_DEVICE env var."""
    device = os.environ.get("CANTEEN_DEVICE", "iphone_14").lower().replace("-", "_")
    if device in DEVICE_PROFILES:
        return DEVICE_PROFILES[device], device
    print(f"⚠ Unknown device '{device}', falling back to iphone_14")
    return DEVICE_PROFILES["iphone_14"], "iphone_14"


# ── helpers ────────────────────────────────────────────────────────────────


def _find_free_port() -> int:
    """Find an available TCP port."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(("", 0))
        return s.getsockname()[1]


# ── fixtures ────────────────────────────────────────────────────────────────


@pytest.fixture(scope="session")
def browser():
    """Launch system Chromium once per test session."""
    pw = sync_playwright().start()
    browser = pw.chromium.launch(
        executable_path="/usr/bin/google-chrome-stable",
        headless=True,
        args=["--no-sandbox", "--disable-gpu"],
        ignore_default_args=CHROME_IGNORE_DEFAULTS,
    )
    yield browser
    browser.close()
    pw.stop()


@pytest.fixture
def test_db_path():
    """Create an isolated temp SQLite DB for each test."""
    fd, path = tempfile.mkstemp(suffix=".db", prefix="canteen_frontend_test_")
    os.close(fd)
    os.environ["CANTEEN_DB_PATH"] = path
    yield path
    # Cleanup DB and WAL/SHM/journal files
    for suffix in ("", "-shm", "-wal", "-journal"):
        p = Path(path + suffix)
        if p.exists():
            p.unlink()


@pytest.fixture
def live_server(test_db_path):
    """Start FastAPI + uvicorn on a random port in a background thread.

    Returns the base URL (e.g. 'http://127.0.0.1:12345').
    """
    port = _find_free_port()
    os.environ["CANTEEN_PORT"] = str(port)

    # Reload the server module so DB_PATH picks up the current
    # CANTEEN_DB_PATH (module-level constant read at import time).
    import server
    importlib.reload(server)
    app = server.app

    t = threading.Thread(
        target=uvicorn.run,
        kwargs={
            "app": "server:app",
            "host": "127.0.0.1",
            "port": port,
            "log_level": "error",
        },
        daemon=True,
    )
    t.start()

    base_url = f"http://127.0.0.1:{port}"

    # Wait for server to be ready
    deadline = time.time() + 10
    import urllib.request

    while time.time() < deadline:
        try:
            urllib.request.urlopen(f"{base_url}/", timeout=1)
            break
        except Exception:
            time.sleep(0.1)
    else:
        raise RuntimeError(f"Server did not start on {base_url} within 10s")

    yield base_url
    # Thread is daemon, will exit when test process ends


@pytest.fixture
def page(browser, live_server):
    """Create a Playwright page pointed at the live server.

    Mobile viewport driven by CANTEEN_DEVICE env var (default: iphone_14).
    Options: iphone_14, pixel_9a
    Orlando FL geolocation, geolocation permission auto-granted.
    """
    device_config, device_name = get_device_config()
    context = browser.new_context(
        viewport=device_config["viewport"],
        user_agent=device_config["user_agent"],
        device_scale_factor=device_config["device_scale_factor"],
        geolocation={"latitude": 28.3852, "longitude": -81.5639},
        permissions=["geolocation"],
    )
    page = context.new_page()
    page.goto(live_server)
    yield page
    context.close()
