"""Tests for the har-derived-api-client optional skill.

Two layers, both stdlib + pytest, no network:
  1. Structural / frontmatter contract on SKILL.md (matches the maintainer
     review checklist for optional skills).
  2. Behavioral: run the real har_to_client.py logic against a synthetic HAR
     fixture and assert it derives the endpoint, collapses id path segments,
     filters static assets, and surfaces the User-Agent replay hint.
"""

import importlib.util
import json
import re
from pathlib import Path

import pytest

SKILL_DIR = (
    Path(__file__).resolve().parents[2]
    / "optional-skills"
    / "web-development"
    / "har-derived-api-client"
)
SKILL_MD = SKILL_DIR / "SKILL.md"
CAPTURE = SKILL_DIR / "scripts" / "har_capture.py"
CAPTURE_CDP = SKILL_DIR / "scripts" / "har_capture_cdp.py"
DERIVE = SKILL_DIR / "scripts" / "har_to_client.py"


@pytest.fixture(scope="module")
def skill_text() -> str:
    return SKILL_MD.read_text(encoding="utf-8")


def _load_module(path: Path, name: str):
    spec = importlib.util.spec_from_file_location(name, path)
    assert spec and spec.loader
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


# --- structural contract ---------------------------------------------------


def test_skill_files_exist():
    assert SKILL_MD.is_file()
    assert CAPTURE.is_file()
    assert CAPTURE_CDP.is_file()
    assert DERIVE.is_file()


def test_frontmatter_present(skill_text: str):
    assert skill_text.startswith("---\n")
    assert skill_text.count("---") >= 2


def test_description_under_sixty_chars(skill_text: str):
    m = re.search(r"^description: (.*)$", skill_text, re.MULTILINE)
    assert m, "no description field"
    desc = m.group(1).strip()
    assert len(desc) <= 60, f"description is {len(desc)} chars (>60): {desc!r}"
    assert desc.endswith("."), "description should end with a period"


def test_required_sections_present(skill_text: str):
    for heading in (
        "## When to Use",
        "## Prerequisites",
        "## How to Run",
        "## Quick Reference",
        "## Procedure",
        "## Pitfalls",
        "## Verification",
    ):
        assert heading in skill_text, f"missing section: {heading}"


# --- behavioral: derivation logic -----------------------------------------


def _make_har() -> dict:
    return {
        "log": {
            "entries": [
                {  # a JSON API call we want derived, with an id path segment
                    "_resourceType": "fetch",
                    "request": {
                        "method": "GET",
                        "url": "https://api.example.com/v1/items/12345/reviews?limit=5",
                        "queryString": [{"name": "limit", "value": "5"}],
                        "headers": [
                            {"name": "User-Agent", "value": "Mozilla/5.0 TestBrowser/1.0"},
                            {"name": "accept", "value": "application/json"},
                            {"name": "referer", "value": "https://example.com/"},
                        ],
                    },
                    "response": {
                        "status": 200,
                        "content": {
                            "mimeType": "application/json",
                            "text": '{"reviews":[{"id":1}]}',
                        },
                    },
                },
                {  # a static asset we must filter out by default
                    "_resourceType": "script",
                    "request": {
                        "method": "GET",
                        "url": "https://cdn.example.com/app.js",
                        "queryString": [],
                        "headers": [{"name": "User-Agent", "value": "Mozilla/5.0 TestBrowser/1.0"}],
                    },
                    "response": {"status": 200, "content": {"mimeType": "application/javascript"}},
                },
            ]
        }
    }


def test_derives_endpoint_and_filters_static(tmp_path, capsys):
    mod = _load_module(DERIVE, "har_to_client_undertest")
    har = tmp_path / "t.har"
    har.write_text(json.dumps(_make_har()), encoding="utf-8")

    import sys

    argv = sys.argv
    try:
        sys.argv = ["har_to_client.py", str(har), "--host", "example.com"]
        rc = mod.main()
    finally:
        sys.argv = argv
    out = capsys.readouterr().out

    assert rc == 0
    # id path segment collapsed to {id}
    assert "GET https://api.example.com/v1/items/{id}/reviews" in out
    # query param surfaced
    assert "limit = 5" in out
    # static JS filtered out
    assert "app.js" not in out
    # boring header dropped, useful one absent from list but UA promoted to hints
    assert "referer" not in out
    # replay hint carries the browser UA
    assert "User-Agent (send this): Mozilla/5.0 TestBrowser/1.0" in out


def test_path_template_collapses_ids():
    mod = _load_module(DERIVE, "har_to_client_undertest2")
    assert mod.path_template("/v1/items/12345/x") == "/v1/items/{id}/x"
    assert mod.path_template("/v1/items/abc/x") == "/v1/items/abc/x"


def test_capture_actions_parse_ok():
    # har_capture imports playwright at module top; only assert the file is
    # syntactically valid and exposes run_action without importing playwright.
    src = CAPTURE.read_text(encoding="utf-8")
    compile(src, str(CAPTURE), "exec")
    assert "def run_action(" in src
    assert 'record_har_content="embed"' in src


def test_cdp_capture_is_valid_and_attaches_not_launches():
    # Covers the CDP pathway (cloud backends / /browser connect). Syntax-check
    # without importing playwright, and assert it attaches (connect_over_cdp)
    # and does NOT close a browser it doesn't own.
    src = CAPTURE_CDP.read_text(encoding="utf-8")
    compile(src, str(CAPTURE_CDP), "exec")
    assert "connect_over_cdp(" in src
    assert 'page.on("request"' in src and 'page.on("response"' in src
    # must not tear down a browser it merely attached to
    assert "browser.close()" not in src


def test_skill_documents_all_browser_pathways(skill_text: str):
    # The skill must route every Hermes browser backend to the right capturer.
    for token in ("Browserbase", "Browser-Use", "Firecrawl", "browser connect",
                  "har_capture_cdp.py", "connect_over_cdp"):
        assert token in skill_text, f"pathway coverage missing: {token}"
