from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path
from typing import Any


ROOT = Path(__file__).resolve().parents[1]
DEFAULT_PROBE = ROOT / "reports" / "1c-template-probes" / "upo_test_auto_20260627T142419Z_670780b4.json"
DEFAULT_BASELINE_DISCOVERY = ROOT / "reports" / "1c-template-baselines" / "Primer3_moxel_schema_discovery.json"
DEFAULT_HISTORY_MATRIX = ROOT / "reports" / "1c-template-baselines" / "Primer3_history_matrix.json"
DEFAULT_PROPERTY_CANDIDATES = ROOT / "reports" / "1c-template-baselines" / "Primer3_property_candidates.json"
DEFAULT_PROPERTY_MANIFEST = ROOT / "reports" / "1c-template-baselines" / "Primer3_moxel_property_experiments.manifest.json"


def rel(path: Path) -> str:
    try:
        return str(path.resolve().relative_to(ROOT))
    except ValueError:
        return str(path)


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


def build_commands(args: argparse.Namespace) -> list[tuple[str, list[str]]]:
    py = sys.executable
    probe_path = Path(args.probe).resolve()
    live_discovery_json = ROOT / "reports" / "1c-template-probes" / "upo_test_auto_moxel_schema_discovery.json"
    live_discovery_md = ROOT / "reports" / "1c-template-probes" / "upo_test_auto_moxel_schema_discovery.md"
    property_json = ROOT / "reports" / "1c-template-baselines" / "Primer3_moxel_property_experiments.json"
    property_md = ROOT / "reports" / "1c-template-baselines" / "Primer3_moxel_property_experiments.md"
    named_range_json = ROOT / "reports" / "1c-template-baselines" / "moxel-named-range-rules.json"
    named_range_md = ROOT / "reports" / "1c-template-baselines" / "moxel-named-range-rules.md"
    registry_json = ROOT / "plugins" / "1c" / "metadata" / "moxel-schema-registry.json"
    registry_md = ROOT / "reports" / "1c-template-baselines" / "moxel-schema-registry.md"
    registry_check = ROOT / "reports" / "1c-template-baselines" / "moxel-schema-registry-check.json"
    registry_verification = ROOT / "reports" / "1c-template-baselines" / "moxel-schema-registry-verification.json"
    next_experiments_json = ROOT / "reports" / "1c-template-baselines" / "moxel-next-experiments.json"
    next_experiments_md = ROOT / "reports" / "1c-template-baselines" / "moxel-next-experiments.md"
    next_action_json = ROOT / "reports" / "1c-template-baselines" / "moxel-next-action.json"
    next_action_md = ROOT / "reports" / "1c-template-baselines" / "moxel-next-action.md"
    next_action_check = ROOT / "reports" / "1c-template-baselines" / "moxel-next-action-check.json"

    commands: list[tuple[str, list[str]]] = []
    if args.capture_live:
        probe_path = ROOT / "reports" / "1c-template-probes" / "latest-live-probe.json"
        probe_markdown = ROOT / "reports" / "1c-template-probes" / "latest-live-probe.md"
        capture_command = [
            py,
            "scripts/capture_1c_template_probe.py",
            "--base-id",
            args.base_id,
            "--label",
            args.label,
            "--output-dir",
            "reports/1c-template-probes",
            "--output-json",
            rel(probe_path),
            "--output-markdown",
            rel(probe_markdown),
            "--scan-limit",
            str(args.scan_limit),
            "--max-cells",
            str(args.max_cells),
        ]
        if args.file_name:
            capture_command.extend(["--file-name", args.file_name])
        commands.append(
            (
                "capture_live_probe",
                capture_command,
            )
        )

    commands.extend(
        [
            (
                "discover_schema",
                [
                    py,
                    "scripts/discover_1c_moxel_schema.py",
                    "--probe-snapshot",
                    rel(probe_path),
                    "--history-matrix",
                    rel(Path(args.history_matrix)),
                    "--property-candidates",
                    rel(Path(args.property_candidates)),
                    "--output-json",
                    rel(live_discovery_json),
                    "--output-markdown",
                    rel(live_discovery_md),
                ],
            ),
            (
                "analyze_named_range_rules",
                [
                    py,
                    "scripts/analyze_1c_moxel_named_range_rules.py",
                    "--probe",
                    rel(probe_path),
                    "--target-name",
                    "R7C2_TEST",
                    "--output-json",
                    rel(named_range_json),
                    "--output-markdown",
                    rel(named_range_md),
                ],
            ),
            (
                "analyze_property_experiments",
                [
                    py,
                    "scripts/analyze_1c_moxel_property_experiments.py",
                    "--manifest",
                    rel(Path(args.property_manifest)),
                    "--emit-default-plan",
                    "--output-json",
                    rel(property_json),
                    "--output-markdown",
                    rel(property_md),
                ],
            ),
            (
                "build_registry",
                [
                    py,
                    "scripts/build_1c_moxel_schema_registry.py",
                    "--discovery",
                    rel(live_discovery_json),
                    "--discovery",
                    rel(Path(args.baseline_discovery)),
                    "--named-range-analysis",
                    rel(named_range_json),
                    "--output-json",
                    rel(registry_json),
                    "--output-markdown",
                    rel(registry_md),
                ],
            ),
            (
                "check_registry",
                [
                    py,
                    "scripts/check_1c_moxel_schema_registry.py",
                    "--registry",
                    rel(registry_json),
                    "--output",
                    rel(registry_check),
                ],
            ),
            (
                "verify_registry",
                [
                    py,
                    "scripts/verify_1c_moxel_schema_registry.py",
                    "--registry",
                    rel(registry_json),
                    "--probe",
                    rel(probe_path),
                    "--output",
                    rel(registry_verification),
                ],
            ),
            (
                "plan_next_experiments",
                [
                    py,
                    "scripts/plan_1c_moxel_next_experiments.py",
                    "--registry",
                    rel(registry_json),
                    "--verification",
                    rel(registry_verification),
                    "--output-json",
                    rel(next_experiments_json),
                    "--output-markdown",
                    rel(next_experiments_md),
                ],
            ),
            (
                "get_next_action",
                [
                    py,
                    "scripts/get_1c_moxel_next_action.py",
                    "--plan",
                    rel(next_experiments_json),
                    "--output-json",
                    rel(next_action_json),
                    "--output-markdown",
                    rel(next_action_md),
                ],
            ),
            (
                "check_next_action",
                [
                    py,
                    "scripts/check_1c_moxel_next_action.py",
                    "--plan",
                    rel(next_experiments_json),
                    "--action",
                    rel(next_action_json),
                    "--output",
                    rel(next_action_check),
                ],
            ),
            (
                "status",
                [
                    py,
                    "scripts/status_1c_moxel.py",
                ],
            ),
        ]
    )
    return commands


def render_markdown(report: dict[str, Any]) -> str:
    lines = ["# 1C MOXCEL Discovery Pipeline", ""]
    lines.append(f"- Status: `{report.get('status')}`")
    lines.append(f"- Steps: `{len(report.get('steps') or [])}`")
    lines.append("")
    lines.append("| Step | Status |")
    lines.append("| --- | --- |")
    for step in report.get("steps") or []:
        lines.append(f"| `{step.get('name')}` | `{step.get('status')}` |")
    lines.append("")
    return "\n".join(lines)


def main() -> int:
    parser = argparse.ArgumentParser(description="Run the complete 1C MOXCEL discovery and registry pipeline.")
    parser.add_argument("--probe", default=str(DEFAULT_PROBE), help="Existing probe snapshot JSON.")
    parser.add_argument("--baseline-discovery", default=str(DEFAULT_BASELINE_DISCOVERY))
    parser.add_argument("--history-matrix", default=str(DEFAULT_HISTORY_MATRIX))
    parser.add_argument("--property-candidates", default=str(DEFAULT_PROPERTY_CANDIDATES))
    parser.add_argument("--property-manifest", default=str(DEFAULT_PROPERTY_MANIFEST))
    parser.add_argument("--capture-live", action="store_true", help="Capture a live probe before running the pipeline.")
    parser.add_argument("--base-id", default="upo_test")
    parser.add_argument("--label", default="pipeline")
    parser.add_argument("--file-name", help="Explicit ConfigCAS file name for live capture.")
    parser.add_argument("--scan-limit", type=int, default=30)
    parser.add_argument("--max-cells", type=int, default=800)
    parser.add_argument("--dry-run", action="store_true")
    parser.add_argument("--report-json", default="reports/1c-template-baselines/moxel-discovery-pipeline.json")
    parser.add_argument("--report-markdown", default="reports/1c-template-baselines/moxel-discovery-pipeline.md")
    args = parser.parse_args()

    steps = []
    failures = []
    for name, command in build_commands(args):
        step = run_step(name, command, dry_run=args.dry_run)
        steps.append(step)
        if step["status"] == "failed":
            failures.append(name)
            break
    report = {
        "schema": "codex_1c_moxel_discovery_pipeline.v1",
        "status": "failed" if failures else "planned" if args.dry_run else "ok",
        "failed_steps": failures,
        "steps": steps,
    }
    json_path = ROOT / args.report_json
    md_path = ROOT / args.report_markdown
    json_path.parent.mkdir(parents=True, exist_ok=True)
    md_path.parent.mkdir(parents=True, exist_ok=True)
    json_path.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
    md_path.write_text(render_markdown(report), encoding="utf-8")
    print(json.dumps({"status": report["status"], "json": rel(json_path), "markdown": rel(md_path), "failed_steps": failures}, ensure_ascii=False, indent=2))
    return 1 if failures else 0


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