"""Post-generation filing package validator.

Re-verifies a previously generated CECL/CCAR filing package:
  - All 8 canonical output files exist
  - SHA-256 checksums match manifest
  - cecl_disclosure.json and ccar_export.json pass schema validation

Stdlib-only (ADR-007).  Exit 0 = pass, exit 1 = fail.
"""

from __future__ import annotations

import hashlib
import json
import time
from pathlib import Path
from typing import Any

from orxaq.credit.filing import FILING_OUTPUT_FILES
from orxaq.credit.regulatory_export import validate_ccar_schema, validate_cecl_schema

__all__ = ["cmd_filing_validate", "validate_filing_package"]


def _sha256(path: Path) -> str:
    """Compute SHA-256 hex digest of a file."""
    h = hashlib.sha256()
    with open(path, "rb") as fh:
        for chunk in iter(lambda: fh.read(65536), b""):
            h.update(chunk)
    return h.hexdigest()


def validate_filing_package(output_dir: str) -> dict[str, Any]:
    """Validate a filing package directory.

    Returns a structured result dict with keys:
      status       "pass" | "fail"
      checks       list of {name, passed, detail}
      files_verified  int
      generated_at str (ISO-8601 UTC)
    """
    out = Path(output_dir)
    checks: list[dict[str, Any]] = []
    generated_at = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())

    # ── Check 1: All 8 canonical files present ────────────────
    missing = [f for f in FILING_OUTPUT_FILES if not (out / f).exists()]
    checks.append(
        {
            "name": "files_present",
            "passed": len(missing) == 0,
            "detail": f"Missing: {missing}"
            if missing
            else f"All {len(FILING_OUTPUT_FILES)} files present",
        }
    )

    # ── Check 2: Manifest exists and parses ───────────────────
    manifest_path = out / "manifest.json"
    manifest: dict[str, Any] = {}
    if manifest_path.exists():
        try:
            manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
            checks.append(
                {"name": "manifest_parseable", "passed": True, "detail": "manifest.json parsed"}
            )
        except json.JSONDecodeError as exc:
            checks.append(
                {"name": "manifest_parseable", "passed": False, "detail": f"JSON error: {exc}"}
            )
    else:
        checks.append(
            {"name": "manifest_parseable", "passed": False, "detail": "manifest.json not found"}
        )

    # ── Check 3: SHA-256 checksums ────────────────────────────
    manifest_files: dict[str, Any] = manifest.get("files", {})
    checksum_results: list[str] = []
    checksum_pass = True
    files_verified = 0

    for fname, meta in manifest_files.items():
        fpath = out / fname
        if not fpath.exists():
            checksum_results.append(f"{fname}: file missing")
            checksum_pass = False
            continue
        expected = meta.get("sha256", "")
        actual = _sha256(fpath)
        if actual != expected:
            checksum_results.append(
                f"{fname}: checksum mismatch (expected {expected[:12]}… got {actual[:12]}…)"
            )
            checksum_pass = False
        else:
            files_verified += 1

    if manifest_files:
        checks.append(
            {
                "name": "sha256_checksums",
                "passed": checksum_pass,
                "detail": "; ".join(checksum_results)
                if checksum_results
                else f"{files_verified} checksums verified",
            }
        )
    else:
        checks.append(
            {"name": "sha256_checksums", "passed": False, "detail": "No file entries in manifest"}
        )

    # ── Check 4: CECL schema validation ──────────────────────
    cecl_path = out / "cecl_disclosure.json"
    if cecl_path.exists():
        try:
            cecl_data = json.loads(cecl_path.read_text(encoding="utf-8"))
            missing_fields = validate_cecl_schema(cecl_data)
            checks.append(
                {
                    "name": "cecl_schema",
                    "passed": len(missing_fields) == 0,
                    "detail": f"Missing fields: {missing_fields}"
                    if missing_fields
                    else "CECL schema valid",
                }
            )
        except json.JSONDecodeError as exc:
            checks.append({"name": "cecl_schema", "passed": False, "detail": f"JSON error: {exc}"})
    else:
        checks.append(
            {"name": "cecl_schema", "passed": False, "detail": "cecl_disclosure.json not found"}
        )

    # ── Check 5: CCAR schema validation ──────────────────────
    ccar_path = out / "ccar_export.json"
    if ccar_path.exists():
        try:
            ccar_data = json.loads(ccar_path.read_text(encoding="utf-8"))
            missing_fields = validate_ccar_schema(ccar_data)
            checks.append(
                {
                    "name": "ccar_schema",
                    "passed": len(missing_fields) == 0,
                    "detail": f"Missing fields: {missing_fields}"
                    if missing_fields
                    else "CCAR schema valid",
                }
            )
        except json.JSONDecodeError as exc:
            checks.append({"name": "ccar_schema", "passed": False, "detail": f"JSON error: {exc}"})
    else:
        checks.append(
            {"name": "ccar_schema", "passed": False, "detail": "ccar_export.json not found"}
        )

    all_passed = all(c["passed"] for c in checks)
    return {
        "status": "pass" if all_passed else "fail",
        "checks": checks,
        "files_verified": files_verified,
        "generated_at": generated_at,
    }


def cmd_filing_validate(output_dir: str, fmt: str = "text") -> dict[str, Any]:
    """CLI entry point: validate a filing package.

    Args:
        output_dir: Path to the filing output directory.
        fmt: "text" (human) or "json".

    Returns structured result dict (status, checks, files_verified, generated_at).
    """
    return validate_filing_package(output_dir)
