"""Report generator: load JSON results and produce a self-contained HTML report."""

from __future__ import annotations

import json
from datetime import datetime, timezone
from pathlib import Path
from string import Template


def load_results_from_dir(directory: str | Path) -> list[dict]:
    """Load all valid JSON result files from a directory.

    Skips files that are not valid JSON or don't have the expected structure
    (must contain "metadata" and "results" keys).
    """
    path = Path(directory)
    if not path.is_dir():
        return []

    results = []
    for json_file in sorted(path.glob("*.json")):
        try:
            data = json.loads(json_file.read_text())
            if isinstance(data, dict) and "metadata" in data and "results" in data:
                results.append(data)
        except (json.JSONDecodeError, OSError):
            continue
    return results


def build_report_data(results: list[dict]) -> dict:
    """Transform a list of result dicts into a comparison structure.

    Returns:
        {
            "databases": [{"name": ..., "passed": ..., "failed": ..., ...}, ...],
            "types": {"clause": {"db1": {"passed": 3, "total": 5}, ...}, ...},
            "comparison": [{"element": ..., "type": ..., "databases": {"db1": {"result": ..., "error": ...}}}, ...],
            "generated_at": "...",
        }
    """
    databases = []
    # element -> {db_name: {result, error}}
    element_map: dict[str, dict] = {}
    # type -> {db_name: {passed, total}}
    type_map: dict[str, dict[str, dict]] = {}

    for run in results:
        meta = run["metadata"]
        db_name = meta.get("database", "unknown")
        databases.append({
            "name": db_name,
            "version": meta.get("database_version") or "",
            "passed": meta.get("passed", 0),
            "failed": meta.get("failed", 0),
            "total": meta.get("total_tests", 0),
            "pass_rate": meta.get("pass_rate", "0%"),
        })

        for r in run["results"]:
            element = r["element"]
            etype = r["type"]

            if element not in element_map:
                element_map[element] = {"element": element, "type": etype, "databases": {}}
            element_map[element]["databases"][db_name] = {
                "result": r["result"],
                "error": r.get("error", ""),
            }

            if etype not in type_map:
                type_map[etype] = {}
            if db_name not in type_map[etype]:
                type_map[etype][db_name] = {"passed": 0, "total": 0}
            type_map[etype][db_name]["total"] += 1
            if r["result"] == "pass":
                type_map[etype][db_name]["passed"] += 1

    comparison = sorted(element_map.values(), key=lambda x: (x["type"], x["element"]))

    return {
        "databases": databases,
        "types": type_map,
        "comparison": comparison,
        "generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC"),
    }


def generate_report(results: list[dict]) -> str:
    """Generate a self-contained HTML report string from result dicts."""
    import importlib.resources as pkg_resources

    report_data = build_report_data(results)
    data_json = json.dumps(report_data, indent=2)

    template_text = (
        pkg_resources.files("opencypher_compliance.templates")
        .joinpath("report.html")
        .read_text(encoding="utf-8")
    )
    template = Template(template_text)
    return template.safe_substitute(REPORT_DATA_JSON=data_json)


def write_report(
    results: list[dict],
    output_dir: str | Path = "./results",
    filename: str = "report.html",
) -> Path:
    """Generate an HTML report and write it to disk.

    Returns the path to the written file.
    """
    html = generate_report(results)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)
    report_path = output_path / filename
    report_path.write_text(html, encoding="utf-8")
    return report_path
