"""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()