"""Tests for the report module."""

import json
import pytest

from opencypher_compliance.report import (
    load_results_from_dir,
    build_report_data,
    generate_report,
    write_report,
)


def _make_result(db_name, tests, database_version=None):
    """Helper: build a result dict matching the runner output format."""
    passed = sum(1 for t in tests if t["result"] == "pass")
    failed = sum(1 for t in tests if t["result"] != "pass")
    total = len(tests)
    rate = f"{round(passed / total * 100)}%" if total else "0%"
    return {
        "metadata": {
            "database": db_name,
            "database_version": database_version,
            "total_tests": total,
            "passed": passed,
            "failed": failed,
            "pass_rate": rate,
            "timestamp": "2026-03-14T00:00:00",
        },
        "results": tests,
        "summary_by_type": {},
    }


SAMPLE_TESTS_A = [
    {"element": "MATCH", "type": "clause", "result": "pass", "duration_ms": 10},
    {"element": "RETURN", "type": "clause", "result": "pass", "duration_ms": 5},
    {"element": "PLUS", "type": "operator", "result": "fail", "error": "Not supported", "duration_ms": 8},
]
SAMPLE_TESTS_B = [
    {"element": "MATCH", "type": "clause", "result": "pass", "duration_ms": 12},
    {"element": "RETURN", "type": "clause", "result": "fail", "error": "Timeout", "duration_ms": 100},
    {"element": "PLUS", "type": "operator", "result": "pass", "duration_ms": 6},
]


class TestLoadResults:
    def test_loads_json_files(self, tmp_path):
        result = _make_result("DB1", SAMPLE_TESTS_A)
        (tmp_path / "db1.json").write_text(json.dumps(result))
        loaded = load_results_from_dir(tmp_path)
        assert len(loaded) == 1
        assert loaded[0]["metadata"]["database"] == "DB1"

    def test_skips_csv_files(self, tmp_path):
        (tmp_path / "results.csv").write_text("a,b,c\n1,2,3")
        result = _make_result("DB1", SAMPLE_TESTS_A)
        (tmp_path / "db1.json").write_text(json.dumps(result))
        loaded = load_results_from_dir(tmp_path)
        assert len(loaded) == 1

    def test_skips_invalid_json(self, tmp_path):
        (tmp_path / "bad.json").write_text("{invalid json")
        loaded = load_results_from_dir(tmp_path)
        assert len(loaded) == 0

    def test_skips_json_without_expected_keys(self, tmp_path):
        (tmp_path / "other.json").write_text(json.dumps({"foo": "bar"}))
        loaded = load_results_from_dir(tmp_path)
        assert len(loaded) == 0

    def test_empty_dir(self, tmp_path):
        loaded = load_results_from_dir(tmp_path)
        assert loaded == []

    def test_nonexistent_dir(self):
        loaded = load_results_from_dir("/nonexistent/path")
        assert loaded == []

    def test_multiple_files_sorted(self, tmp_path):
        (tmp_path / "b_db.json").write_text(json.dumps(_make_result("B", SAMPLE_TESTS_A)))
        (tmp_path / "a_db.json").write_text(json.dumps(_make_result("A", SAMPLE_TESTS_B)))
        loaded = load_results_from_dir(tmp_path)
        assert len(loaded) == 2
        assert loaded[0]["metadata"]["database"] == "A"
        assert loaded[1]["metadata"]["database"] == "B"


class TestBuildReportData:
    def test_basic_structure(self):
        results = [
            _make_result("Neo4j", SAMPLE_TESTS_A),
            _make_result("FalkorDB", SAMPLE_TESTS_B),
        ]
        data = build_report_data(results)
        assert len(data["databases"]) == 2
        assert "types" in data
        assert "comparison" in data
        assert "generated_at" in data

    def test_databases_stats(self):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        data = build_report_data(results)
        db = data["databases"][0]
        assert db["name"] == "Neo4j"
        assert db["passed"] == 2
        assert db["failed"] == 1
        assert db["total"] == 3

    def test_comparison_matrix(self):
        results = [
            _make_result("Neo4j", SAMPLE_TESTS_A),
            _make_result("FalkorDB", SAMPLE_TESTS_B),
        ]
        data = build_report_data(results)
        comp = {c["element"]: c for c in data["comparison"]}
        assert comp["MATCH"]["databases"]["Neo4j"]["result"] == "pass"
        assert comp["MATCH"]["databases"]["FalkorDB"]["result"] == "pass"
        assert comp["RETURN"]["databases"]["FalkorDB"]["result"] == "fail"

    def test_type_breakdown(self):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        data = build_report_data(results)
        assert data["types"]["clause"]["Neo4j"]["passed"] == 2
        assert data["types"]["clause"]["Neo4j"]["total"] == 2
        assert data["types"]["operator"]["Neo4j"]["passed"] == 0
        assert data["types"]["operator"]["Neo4j"]["total"] == 1

    def test_database_version_included(self):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A, database_version="Neo4j/5.26")]
        data = build_report_data(results)
        assert data["databases"][0]["version"] == "Neo4j/5.26"

    def test_database_version_null_becomes_empty(self):
        results = [_make_result("FalkorDB", SAMPLE_TESTS_A, database_version=None)]
        data = build_report_data(results)
        assert data["databases"][0]["version"] == ""

    def test_comparison_sorted_by_type_then_element(self):
        results = [_make_result("DB", SAMPLE_TESTS_A)]
        data = build_report_data(results)
        elements = [c["element"] for c in data["comparison"]]
        assert elements == ["MATCH", "RETURN", "PLUS"]


class TestGenerateReport:
    def test_produces_html(self):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        html = generate_report(results)
        assert html.startswith("<!DOCTYPE html>")
        assert "openCypher Compliance Report" in html

    def test_embeds_data(self):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        html = generate_report(results)
        assert '"Neo4j"' in html
        assert '"MATCH"' in html

    def test_no_unsubstituted_placeholders(self):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        html = generate_report(results)
        assert "$REPORT_DATA_JSON" not in html


class TestWriteReport:
    def test_writes_html_file(self, tmp_path):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        path = write_report(results, output_dir=tmp_path)
        assert path.exists()
        assert path.name == "report.html"
        content = path.read_text()
        assert "<!DOCTYPE html>" in content

    def test_custom_filename(self, tmp_path):
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        path = write_report(results, output_dir=tmp_path, filename="custom.html")
        assert path.name == "custom.html"

    def test_creates_output_dir(self, tmp_path):
        out = tmp_path / "subdir" / "reports"
        results = [_make_result("Neo4j", SAMPLE_TESTS_A)]
        path = write_report(results, output_dir=out)
        assert path.exists()
