"""Verifier for sec-005: XSS Vulnerability Scan."""

import json
from pathlib import Path

import pytest


@pytest.fixture
def workspace(request):
    """Resolve the workspace path from the --workspace CLI flag."""
    return Path(request.config.getoption("--workspace"))


@pytest.fixture
def report(workspace):
    """Load and return the XSS report JSON."""
    path = workspace / "xss_report.json"
    assert path.exists(), "xss_report.json not found in workspace"
    data = json.loads(path.read_text())
    assert isinstance(data, list), "xss_report.json must contain a JSON array"
    return data


def test_report_file_exists(workspace):
    """xss_report.json must exist."""
    assert (workspace / "xss_report.json").exists()


def test_at_least_six_vulnerabilities(report):
    """Must detect at least 6 XSS vulnerabilities."""
    assert len(report) >= 6, f"Expected at least 6 findings, got {len(report)}"


def test_each_finding_has_required_fields(report):
    """Each finding must have file, line, type, description, severity."""
    for entry in report:
        assert "file" in entry, "Missing 'file' field"
        assert "line" in entry, "Missing 'line' field"
        assert "type" in entry, "Missing 'type' field"
        assert "description" in entry, "Missing 'description' field"
        assert "severity" in entry, "Missing 'severity' field"


def test_profile_triple_braces_found(report):
    """profile.html triple-brace unescaped output must be detected."""
    matches = [r for r in report if r["file"] == "profile.html"]
    assert len(matches) >= 1, "No vulnerability found in profile.html"
    desc_text = " ".join(r.get("description", "") for r in matches).lower()
    assert "unescape" in desc_text or "raw" in desc_text or "triple" in desc_text or "bio" in desc_text


def test_search_inline_js_found(report):
    """search.html inline JavaScript vulnerability must be detected."""
    matches = [r for r in report if r["file"] == "search.html"]
    assert len(matches) >= 1, "No vulnerability found in search.html"


def test_comment_safe_filter_found(report):
    """comment.html |safe filter vulnerability must be detected."""
    matches = [r for r in report if r["file"] == "comment.html"]
    assert len(matches) >= 1, "No vulnerability found in comment.html"
    desc_text = " ".join(r.get("description", "") for r in matches).lower()
    assert "safe" in desc_text or "unescape" in desc_text or "filter" in desc_text


def test_dashboard_url_injection_found(report):
    """dashboard.html URL attribute injection must be detected."""
    matches = [r for r in report if r["file"] == "dashboard.html"]
    assert len(matches) >= 1, "No vulnerability found in dashboard.html"


def test_settings_dom_xss_found(report):
    """settings.html innerHTML DOM XSS must be detected."""
    matches = [r for r in report if r["file"] == "settings.html"]
    assert len(matches) >= 1, "No vulnerability found in settings.html"


def test_valid_types(report):
    """Finding types must be valid XSS categories."""
    valid_types = {
        "unescaped_output", "attribute_injection", "inline_js",
        "dom_injection", "stored_xss", "reflected_xss", "dom_xss",
        "xss", "script_injection",
    }
    for entry in report:
        assert entry["type"].lower().replace("-", "_").replace(" ", "_") in valid_types or \
               any(vt in entry["type"].lower() for vt in ["xss", "inject", "unescape", "dom", "script"]), \
            f"Unexpected type: {entry['type']}"


def test_severity_values(report):
    """Severity must be high, medium, or low."""
    for entry in report:
        assert entry["severity"] in ("high", "medium", "low"), (
            f"Invalid severity: {entry['severity']}"
        )
