#!/usr/bin/env python3
"""FlowSpec fix runner scaffold.

The first version performs validation checkpoints and prints the intended next
action. Real Codex/GitLab orchestration can wrap this script.
"""

from __future__ import annotations

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


def run_validate(work_dir: Path) -> dict:
    package_root = Path(__file__).resolve().parents[1]
    node_cli = package_root / "bin" / "flowspec.js"
    python_cli = package_root / "cli" / "flowspec.py"
    if node_cli.exists():
        command = ["node", str(node_cli), "validate", "--work-dir", str(work_dir), "--json"]
    elif python_cli.exists():
        command = [sys.executable, str(python_cli), "validate", "--work-dir", str(work_dir), "--json"]
    else:
        command = ["flowspec", "validate", "--work-dir", str(work_dir), "--json"]
    proc = subprocess.run(
        command,
        text=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        check=False,
    )
    if proc.returncode not in (0, 1):
        raise SystemExit(proc.stderr or proc.stdout)
    return json.loads(proc.stdout)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Run FlowSpec fix preflight")
    parser.add_argument("--work-dir", required=True)
    parser.add_argument("--issue-id", required=True)
    parser.add_argument("--checkpoint", choices=["before", "after-change", "before-mr"], default="before")
    parser.add_argument("--no-lock", action="store_true")
    return parser.parse_args()


def issue_path(work_dir: Path, issue_id: str) -> Path:
    return work_dir / "flowspec" / "issues" / f"{issue_id}.json"


def load_issue(work_dir: Path, issue_id: str) -> dict:
    path = issue_path(work_dir, issue_id)
    if not path.exists():
        return {"issue_id": issue_id, "labels": []}
    return json.loads(path.read_text(encoding="utf-8"))


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


def add_label(issue: dict, label: str) -> None:
    labels = issue.setdefault("labels", [])
    if label not in labels:
        labels.append(label)


def remove_label(issue: dict, label: str) -> None:
    labels = issue.setdefault("labels", [])
    issue["labels"] = [item for item in labels if item != label]


def apply_checkpoint_state(work_dir: Path, issue_id: str, checkpoint: str, validation: dict, no_lock: bool) -> None:
    issue = load_issue(work_dir, issue_id)
    issue["issue_id"] = issue_id
    lock = work_dir / "flowspec" / "issues" / f"{issue_id}.codex-running.lock"

    if checkpoint == "before" and not no_lock:
        if lock.exists():
            add_label(issue, "human-needed")
            issue["runner_blocker"] = f"codex-running lock exists: {lock}"
            save_issue(work_dir, issue)
            raise SystemExit(f"Codex runner lock exists for {issue_id}: {lock}")
        lock.parent.mkdir(parents=True, exist_ok=True)
        lock.write_text("codex-running\n", encoding="utf-8")
        add_label(issue, "codex-running")

    if not validation.get("can_codex_continue"):
        severities = {item.get("severity") for item in validation.get("issues", [])}
        add_label(issue, "human-needed" if "human-needed" in severities else "needs-info")
        issue["runner_blocker"] = validation.get("issues", [])

    if checkpoint == "before-mr" and validation.get("can_codex_continue"):
        remove_label(issue, "codex-running")
        add_label(issue, "fix-proposed")
        issue["mr_ready"] = True
        if lock.exists():
            lock.unlink()

    save_issue(work_dir, issue)


def main() -> int:
    args = parse_args()
    work_dir = Path(args.work_dir)
    payload = run_validate(work_dir)
    apply_checkpoint_state(work_dir, args.issue_id, args.checkpoint, payload, args.no_lock)
    print(json.dumps(payload, ensure_ascii=False, indent=2))
    if not payload.get("can_codex_continue"):
        print(f"FlowSpec fix blocked at checkpoint {args.checkpoint} for issue {args.issue_id}.", file=sys.stderr)
        return 1
    print(f"FlowSpec fix may continue at checkpoint {args.checkpoint} for issue {args.issue_id}.")
    return 0


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