from __future__ import annotations

import json
from pathlib import Path

import testing.ci.quality_gate as quality_gate_module
from testing.ci.quality_gate import (
    _js_node_issues,
    _python_node_issues,
    check_coverage,
    check_file_sizes,
    run_gate,
)


def test_check_file_sizes_flags_overlong_files(tmp_path: Path) -> None:
    path = tmp_path / "tool.py"
    path.write_text("\n".join(f"line {idx}" for idx in range(7)))

    issues = check_file_sizes([path], max_lines=5)

    assert issues and issues[0].check == "loc"
    assert "exceeds 5" in issues[0].message


def test_docstring_helpers_accept_contract_comments_and_docstrings(tmp_path: Path) -> None:
    py_path = tmp_path / "sample.py"
    py_path.write_text(
        '"""module docs"""\n\n'
        'def documented():\n'
        '    """Explain what the helper does."""\n'
        '    return 1\n\n'
        'def tiny_private_helper():\n'
        '    return 2\n\n'
        'def missing_contract(value):\n'
        '    if value:\n'
        '        return value\n'
        '    if value == 0:\n'
        '        return "zero"\n'
        '    if value is None:\n'
        '        return "none"\n'
        '    if isinstance(value, str):\n'
        '        return value.strip()\n'
        '    return "fallback"\n'
    )
    js_path = tmp_path / "sample.js"
    js_path.write_text(
        '/**\n'
        ' * WHY: the helper needs a contract for the gate.\n'
        ' * @param {string} name - service name.\n'
        ' * @returns {string} icon label.\n'
        ' */\n'
        'function pickIcon(name) {\n'
        '  return name;\n'
        '}\n'
    )

    py_issues = _python_node_issues(py_path)
    js_issues = _js_node_issues(js_path)

    assert any(issue.message.endswith("missing_contract") for issue in py_issues)
    assert js_issues == []


def test_check_coverage_reads_backend_and_frontend_reports(tmp_path: Path) -> None:
    backend_report = tmp_path / "backend.xml"
    backend_report.write_text(
        '<coverage><packages><package><classes>'
        '<class filename="backend/atlas_portal/app_factory.py" line-rate="1.0" branch-rate="1.0"/>'
        '</classes></package></packages></coverage>'
    )
    frontend_report = tmp_path / "frontend.json"
    frontend_report.write_text(
        json.dumps(
            {
                "src/auth.js": {
                    "lines": {"pct": 100},
                    "statements": {"pct": 100},
                    "branches": {"pct": 100},
                    "functions": {"pct": 100},
                }
            }
        )
    )

    issues = check_coverage(
        [Path("backend/atlas_portal/app_factory.py"), Path("frontend/src/auth.js")],
        backend_report=backend_report,
        frontend_report=frontend_report,
        threshold=95,
    )

    assert issues == []


def test_run_gate_reports_workspace_coverage_and_loc_totals(tmp_path: Path) -> None:
    root_before = quality_gate_module.ROOT
    quality_gate_module.ROOT = tmp_path
    try:
        backend_dir = tmp_path / "backend" / "atlas_portal"
        frontend_dir = tmp_path / "frontend" / "src"
        backend_dir.mkdir(parents=True)
        frontend_dir.mkdir(parents=True)

        (backend_dir / "app_factory.py").write_text(
            '"""Factory docs."""\n\n'
            "def create_app():\n"
            '    """Create the app."""\n'
            "    return object()\n"
        )
        (backend_dir / "too_long.py").write_text("\n".join(f"line_{idx}" for idx in range(501)))
        (frontend_dir / "auth.js").write_text(
            "/**\n"
            " * WHY: auth wrapper exists.\n"
            " * @param {string} token - jwt.\n"
            " * @returns {string} token.\n"
            " */\n"
            "function auth(token) {\n"
            "  return token;\n"
            "}\n"
        )

        backend_report = tmp_path / "backend.xml"
        backend_report.write_text(
            '<coverage><packages><package><classes>'
            '<class filename="backend/atlas_portal/app_factory.py" line-rate="1.0" branch-rate="1.0"/>'
            '</classes></package></packages></coverage>'
        )
        frontend_report = tmp_path / "frontend.json"
        frontend_report.write_text(
            json.dumps(
                {
                    "src/auth.js": {
                        "lines": {"pct": 100},
                        "statements": {"pct": 100},
                        "branches": {"pct": 100},
                        "functions": {"pct": 100},
                    }
                }
            )
        )

        contract = {
            "managed_files": [
                "backend/atlas_portal/app_factory.py",
                "backend/atlas_portal/too_long.py",
            ],
            "docstring_files": ["backend/atlas_portal/app_factory.py"],
            "coverage_files": [
                "backend/atlas_portal/app_factory.py",
                "frontend/src/auth.js",
            ],
            "max_lines": 500,
            "coverage_threshold_pct": 95,
        }
        contract_path = tmp_path / "contract.json"
        contract_path.write_text(json.dumps(contract))

        issues, report = run_gate(contract_path, backend_coverage=backend_report, frontend_coverage=frontend_report)

        assert any(issue.check == "loc" for issue in issues)
        assert report["workspace_line_coverage_percent"] == 100.0
        assert report["source_files_total"] == 2
        assert report["source_lines_over_500"] == 1
    finally:
        quality_gate_module.ROOT = root_before
