"""JavaScript module tests. Skipped unless pytest is run with --js-tests."""

from __future__ import annotations

import importlib.util
import sys
from collections.abc import Iterator
from pathlib import Path
from types import ModuleType
from typing import Any, cast

import pytest
from pygitweb.static_tests.js_runtime import JsPage, StaticServer, _NavGuard


class _FileModule(pytest.Module):
    def _getobj(self) -> ModuleType:
        name = "js_tests_" + self.path.stem.replace("-", "_")
        spec = importlib.util.spec_from_file_location(name, self.path)
        if spec is None or spec.loader is None:
            raise ImportError(f"cannot load {self.path}")
        module = importlib.util.module_from_spec(spec)
        sys.modules[name] = module
        spec.loader.exec_module(module)
        return module


@pytest.hookimpl(hookwrapper=True)
def pytest_collect_file(file_path: Path, parent: pytest.Collector) -> object:
    outcome = yield
    if file_path.suffix != ".py" or not file_path.name.startswith("test_") or "-" not in file_path.name:
        return
    # pytest 9 gathers every pytest_collect_file result, so the default collector
    # would import this hyphenated module a second time.
    cast(Any, outcome).force_result([_FileModule.from_parent(parent, path=file_path)])


@pytest.fixture(scope="session")
def _js_browser() -> Iterator[tuple[Any, str]]:
    pytest.importorskip("playwright.sync_api")
    from playwright.sync_api import sync_playwright

    server = StaticServer()
    server.start()
    try:
        with sync_playwright() as playwright:
            browser = playwright.chromium.launch(headless=True)
            try:
                yield browser, server.base_url
            finally:
                browser.close()
    finally:
        server.close()


@pytest.fixture
def js(_js_browser: tuple[Any, str]) -> Iterator[JsPage]:
    browser, base_url = _js_browser
    page = browser.new_page()
    page.set_default_timeout(8000)
    guard = _NavGuard()
    page.route("**/*", guard.handle)
    page.goto(base_url + "/", wait_until="domcontentloaded")
    guard.current = page.url
    guard.locked = True
    js_page = JsPage(page, guard)
    yield js_page
    js_page.close()