from __future__ import annotations

import argparse
import json
import subprocess
import sys
import tempfile
from pathlib import Path

import yaml


ROOT = Path(__file__).resolve().parents[1]
PLUGIN = ROOT / "plugins" / "1c"
DEFAULT_REPORT = ROOT / "reports" / "1c-plugin-health.json"


def run(command: list[str], *, allow_fail: bool = False) -> dict:
    result = subprocess.run(
        command,
        cwd=ROOT,
        text=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        check=False,
    )
    status = "ok" if result.returncode == 0 else "failed"
    if allow_fail and result.returncode != 0:
        status = "blocked"
    return {
        "command": command,
        "status": status,
        "returncode": result.returncode,
        "stdout": result.stdout.strip(),
        "stderr": result.stderr.strip(),
    }


def prepare_rag_smoke_index(temp_path: Path) -> list[dict]:
    rag_source = temp_path / "metadata.health.generated.md"
    corpus = temp_path / "rag_corpus.jsonl"
    manifest = temp_path / "rag_manifest.json"
    index = temp_path / "rag_index.json"
    steps = [
        [
            sys.executable,
            "scripts/convert_1c_metadata_to_rag.py",
            "--input",
            "plugins/1c/metadata/examples/metadata.example.json",
            "--output",
            str(rag_source),
        ],
        [
            sys.executable,
            "scripts/convert_1c_bsl_modules_to_rag.py",
            "--input",
            "plugins/1c/metadata/examples/bsl-modules.example.json",
            "--output",
            str(temp_path / "bsl.health.generated.md"),
        ],
        [
            sys.executable,
            "scripts/validate_1c_rag_sources.py",
            "--source-dir",
            str(temp_path),
        ],
        [
            sys.executable,
            "scripts/prepare_1c_rag_corpus.py",
            "--source-dir",
            str(temp_path),
            "--output",
            str(corpus),
            "--manifest",
            str(manifest),
        ],
        [
            sys.executable,
            "scripts/build_1c_rag_index.py",
            "--corpus",
            str(corpus),
            "--output",
            str(index),
        ],
    ]
    return [run(step, allow_fail=True) for step in steps]


def read_yaml(path: Path) -> dict:
    with path.open("r", encoding="utf-8") as handle:
        data = yaml.safe_load(handle)
    if not isinstance(data, dict):
        raise ValueError(f"{path} must contain a YAML mapping")
    return data


def check_required_files() -> dict:
    required = [
        PLUGIN / "plugin.yaml",
        PLUGIN / "prompts" / "system.md",
        PLUGIN / "prompts" / "rag-answer.md",
        PLUGIN / "rag" / "profiles.yaml",
        PLUGIN / "rag" / "quality-smoke.json",
        PLUGIN / "rag" / "profile-routing-smoke.json",
        PLUGIN / "tools" / "tool-contract.yaml",
        PLUGIN / "connector" / "contracts" / "openapi.yaml",
        PLUGIN / "connector" / "policies" / "read-only-query.yaml",
        PLUGIN / "connector" / "policies" / "change-workflow.yaml",
        PLUGIN / "connector" / "policies" / "config-layer-write-policy.yaml",
        PLUGIN / "connector" / "Dockerfile",
        PLUGIN / "connector" / "docker-compose.yml",
        PLUGIN / "connector" / ".env.example",
        PLUGIN / "connector" / "pyproject.toml",
        PLUGIN / "connector" / "service.yaml",
        PLUGIN / "metadata" / "schema.json",
        PLUGIN / "metadata" / "moxel-schema-registry.json",
        PLUGIN / "metadata" / "examples" / "metadata.example.json",
        PLUGIN / "metadata" / "examples" / "metadata-v2.example.json",
        PLUGIN / "metadata" / "examples" / "bsl-modules.example.json",
        PLUGIN / "schemas" / "metadata-snapshot-v2.schema.json",
        PLUGIN / "schemas" / "bsl-module-snapshot.schema.json",
        PLUGIN / "schemas" / "moxel-schema-registry.schema.json",
        PLUGIN / "training" / "examples" / "instruction.examples.jsonl",
        PLUGIN / "training" / "configs" / "qwen3-coder-30b-a3b-lora.yaml",
        PLUGIN / "evals" / "smoke.yaml",
    ]
    missing = [str(path.relative_to(ROOT)) for path in required if not path.exists()]
    return {
        "status": "ok" if not missing else "failed",
        "missing": missing,
    }


def summarize_manifest() -> dict:
    manifest = read_yaml(PLUGIN / "plugin.yaml")
    return {
        "id": manifest.get("id"),
        "version": manifest.get("version"),
        "status": manifest.get("status"),
        "tasks": manifest.get("tasks") or [],
        "entrypoints": sorted((manifest.get("entrypoints") or {}).keys()),
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="Run 1C plugin health checks.")
    parser.add_argument("--report", type=Path, default=DEFAULT_REPORT)
    parser.add_argument("--print", action="store_true")
    parser.add_argument(
        "--no-report",
        action="store_true",
        help="Do not write a health report file; useful for clean local checks.",
    )
    args = parser.parse_args()

    with tempfile.TemporaryDirectory(prefix="llm-1c-health-") as temp_dir:
        temp_index = Path(temp_dir) / "rag_index.json"
        commands = {
            "metadata_example": [
                sys.executable,
                "scripts/validate_1c_metadata_snapshot.py",
                "plugins/1c/metadata/examples/metadata.example.json",
            ],
            "metadata_v2_example": [
                sys.executable,
                "scripts/validate_1c_metadata_snapshot.py",
                "plugins/1c/metadata/examples/metadata-v2.example.json",
            ],
            "bsl_modules_example": [
                sys.executable,
                "scripts/validate_1c_bsl_modules.py",
                "plugins/1c/metadata/examples/bsl-modules.example.json",
            ],
            "readonly_query_allowed": [
                sys.executable,
                "scripts/validate_1c_readonly_query.py",
                "--query",
                "ВЫБРАТЬ Первые 10 Ссылка ИЗ Справочник.Номенклатура",
            ],
            "training_examples": [
                sys.executable,
                "scripts/validate_1c_training_data.py",
                "plugins/1c/training/examples/instruction.examples.jsonl",
            ],
            "evals": [sys.executable, "scripts/validate_evals.py", "plugins/1c/evals/smoke.yaml"],
            "connector_standalone_check": [sys.executable, "scripts/check_1c_connector_standalone.py"],
            "write_plan_contract": [sys.executable, "scripts/check_1c_write_plan_contract.py"],
            "bsl_symbol_check": [sys.executable, "scripts/check_1c_bsl_symbol_resolver.py"],
            "code_symbol_contract": [sys.executable, "scripts/check_1c_code_symbol_contract.py"],
            "module_origin_contract": [sys.executable, "scripts/check_1c_module_origin_contract.py"],
            "extension_action_contract": [sys.executable, "scripts/check_1c_extension_action_contract.py"],
            "moxel_schema_registry_contract": [
                sys.executable,
                "scripts/check_1c_moxel_schema_registry.py",
                "--registry",
                "plugins/1c/metadata/moxel-schema-registry.json",
                "--output",
                str(Path(temp_dir) / "moxel-schema-registry-check.json"),
            ],
            "moxel_status": [
                sys.executable,
                "scripts/status_1c_moxel.py",
                "--output-json",
                str(Path(temp_dir) / "moxel-status.json"),
                "--output-markdown",
                str(Path(temp_dir) / "moxel-status.md"),
            ],
            "rag_prompt_guardrails": [
                sys.executable,
            "scripts/check_1c_rag_prompt.py",
            "--index",
            str(temp_index),
        ],
        "rag_quality": [
            sys.executable,
            "scripts/check_1c_rag_quality.py",
            "--index",
            str(temp_index),
        ],
        "rag_profile_routing": [
            sys.executable,
            "scripts/check_1c_rag_profiles.py",
        ],
        "training_preflight": [sys.executable, "scripts/preflight_1c_training.py"],
        }

        checks = {
            "manifest": summarize_manifest(),
            "required_files": check_required_files(),
            "rag_smoke_prepare": prepare_rag_smoke_index(Path(temp_dir)),
            "commands": {},
        }

        for name, command in commands.items():
            checks["commands"][name] = run(
                command,
                allow_fail=name in {"training_preflight"},
            )

    failed = []
    for name, result in checks["commands"].items():
        if result["status"] == "failed":
            failed.append(name)
    if checks["required_files"]["status"] == "failed":
        failed.append("required_files")

    report = {
        "plugin": "1c",
        "status": "failed" if failed else "ok",
        "failed_checks": failed,
        "checks": checks,
    }

    if not args.no_report:
        args.report.parent.mkdir(parents=True, exist_ok=True)
        args.report.write_text(
            json.dumps(report, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )

    if args.print:
        print(json.dumps(report, ensure_ascii=False, indent=2))
    else:
        if not args.no_report:
            print(f"Wrote 1C plugin health report to {args.report}")
        print(f"Status: {report['status']}")

    return 1 if failed else 0


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