#!/usr/bin/env python3
"""Aggregate final validation gates for a staged 1C extension."""

from __future__ import annotations

import argparse
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from check_1c_extension_staging import check_staging
from check_1c_extension_validation_evidence import check_evidence


def load_json(path: Path) -> dict[str, Any]:
    return json.loads(path.read_text(encoding="utf-8-sig"))


def write_json(path: Path, data: dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def issue(severity: str, code: str, message: str, *, path: Path | str | None = None, detail: dict[str, Any] | None = None) -> dict[str, Any]:
    result: dict[str, Any] = {"severity": severity, "code": code, "message": message}
    if path is not None:
        result["path"] = str(path)
    if detail:
        result["detail"] = detail
    return result


def collect_gate(name: str, data: dict[str, Any]) -> dict[str, Any]:
    return {
        "name": name,
        "schema": data.get("schema"),
        "passed": data.get("passed"),
        "status": data.get("status"),
        "counts": data.get("counts"),
    }


def check_release(plan_path: Path, evidence_root: Path | None = None) -> dict[str, Any]:
    findings: list[dict[str, Any]] = []
    if not plan_path.exists():
        findings.append(issue("error", "missing_validation_plan", "Validation plan is missing.", path=plan_path))
        return build_result(plan_path, None, {}, {}, findings)

    plan = load_json(plan_path)
    if plan.get("schema") != "onec_extension_validation_plan.v1":
        findings.append(issue("error", "invalid_validation_plan_schema", "Validation plan schema is not onec_extension_validation_plan.v1.", path=plan_path, detail={"schema": plan.get("schema")}))

    if plan.get("status") != "ready_for_disposable_validation":
        findings.append(issue("error", "validation_plan_not_ready", "Validation plan must be ready_for_disposable_validation.", path=plan_path, detail={"status": plan.get("status")}))

    staging_dir = Path(str(plan.get("staging_dir") or ""))
    staging_check = check_staging(staging_dir) if staging_dir else {"schema": "onec_extension_staging_check.v1", "passed": False, "counts": {"errors": 1}, "findings": []}
    if not staging_check.get("passed"):
        findings.append(issue("error", "staging_check_failed", "Staging check failed.", path=staging_dir, detail={"counts": staging_check.get("counts")}))

    evidence_check = check_evidence(plan_path, evidence_root)
    if not evidence_check.get("passed"):
        findings.append(issue("error", "validation_evidence_check_failed", "Validation evidence check failed.", path=evidence_check.get("evidence_root"), detail={"counts": evidence_check.get("counts")}))

    safety = plan.get("safety") if isinstance(plan.get("safety"), dict) else {}
    expected_safety = {
        "production_base_allowed": False,
        "sql_write_allowed": False,
        "source_extension_write_allowed": False,
        "disposable_base_required": True,
    }
    for key, expected in expected_safety.items():
        if safety.get(key) is not expected:
            findings.append(issue("error", "invalid_release_safety_flag", "Validation plan safety flag has an unexpected value.", path=plan_path, detail={"flag": key, "expected": expected, "actual": safety.get(key)}))

    return build_result(plan_path, plan, staging_check, evidence_check, findings)


def build_result(plan_path: Path, plan: dict[str, Any] | None, staging_check: dict[str, Any], evidence_check: dict[str, Any], findings: list[dict[str, Any]]) -> dict[str, Any]:
    errors = [row for row in findings if row.get("severity") == "error"]
    warnings = [row for row in findings if row.get("severity") == "warning"]
    return {
        "schema": "onec_extension_validation_release_check.v1",
        "created_at_utc": datetime.now(timezone.utc).isoformat(),
        "plan_path": str(plan_path),
        "staging_dir": (plan or {}).get("staging_dir"),
        "bundle_dir": (plan or {}).get("bundle_dir"),
        "preferred_extension": (plan or {}).get("preferred_extension"),
        "passed": not errors,
        "status": "validated_for_human_review" if not errors else "blocked",
        "safety": {
            "production_apply_allowed": False,
            "automatic_apply_allowed": False,
            "human_approval_required": True,
        },
        "gates": [
            {
                "name": "validation_plan",
                "schema": (plan or {}).get("schema"),
                "passed": (plan or {}).get("status") == "ready_for_disposable_validation",
                "status": (plan or {}).get("status"),
            },
            collect_gate("staging_check", staging_check),
            collect_gate("validation_evidence_check", evidence_check),
        ],
        "findings": findings,
        "counts": {
            "errors": len(errors),
            "warnings": len(warnings),
        },
        "next_actions": [
            "Review validation evidence and changed files manually.",
            "Do not apply to production automatically.",
            "If approved, perform production action through the approved human-controlled 1C release process.",
        ] if not errors else [
            "Fix failed gates before review.",
            "Do not package, apply, or release this extension from the current evidence.",
        ],
        "details": {
            "staging_check": staging_check,
            "validation_evidence_check": evidence_check,
        },
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="Aggregate final validation gates for a staged 1C extension.")
    parser.add_argument("--plan", type=Path, required=True)
    parser.add_argument("--evidence-root", type=Path)
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()

    result = check_release(args.plan, args.evidence_root)
    if args.output:
        write_json(args.output, result)
    print(json.dumps({"output": str(args.output) if args.output else None, "passed": result["passed"], "status": result["status"], "counts": result["counts"]}, ensure_ascii=False))
    return 0 if result["passed"] else 2


if __name__ == "__main__":
    raise SystemExit(main())
