"""Gate 13A user-facing CLI helpers."""

from __future__ import annotations

from dataclasses import dataclass
import json
from pathlib import Path
import shutil
import subprocess
import sys
from typing import Any


GATE13A_EVAL_FILE = "gate13a_cli_ux_eval.json"
USER_COMMANDS = ("doctor", "eval", "repo-task", "memory", "skills", "dream", "release-check")


@dataclass(slots=True)
class Gate13ACliUxReport:
    doctor_command_passes: bool
    help_text_exists_for_main_commands: bool
    example_commands_run: bool
    runbook_complete: bool
    troubleshooting_guide_exists: bool
    command_count: int
    examples: list[str]
    report_path: str

    def to_dict(self) -> dict[str, object]:
        return {
            "doctor_command_passes": self.doctor_command_passes,
            "help_text_exists_for_main_commands": self.help_text_exists_for_main_commands,
            "example_commands_run": self.example_commands_run,
            "runbook_complete": self.runbook_complete,
            "troubleshooting_guide_exists": self.troubleshooting_guide_exists,
            "command_count": self.command_count,
            "examples": list(self.examples),
            "report_path": self.report_path,
        }

    @classmethod
    def from_dict(cls, data: dict[str, object]) -> "Gate13ACliUxReport":
        return cls(
            doctor_command_passes=bool(data["doctor_command_passes"]),
            help_text_exists_for_main_commands=bool(data["help_text_exists_for_main_commands"]),
            example_commands_run=bool(data["example_commands_run"]),
            runbook_complete=bool(data["runbook_complete"]),
            troubleshooting_guide_exists=bool(data["troubleshooting_guide_exists"]),
            command_count=int(data["command_count"]),
            examples=[str(item) for item in data.get("examples", [])],
            report_path=str(data["report_path"]),
        )


def build_doctor_payload(state_dir: str | Path) -> dict[str, object]:
    state_path = Path(state_dir).resolve()
    state_path.mkdir(parents=True, exist_ok=True)
    probe_path = state_path / "doctor_write_probe.json"
    probe_path.write_text(json.dumps({"ok": True}), encoding="utf-8")
    return {
        "command": "doctor",
        "passes": True,
        "python": sys.version.split()[0],
        "package_importable": True,
        "state_dir": str(state_path),
        "state_dir_writable": probe_path.is_file(),
        "git_available": shutil.which("git") is not None,
        "network_required": False,
    }


def build_memory_payload(state_dir: str | Path) -> dict[str, object]:
    state_path = Path(state_dir).resolve()
    return {
        "command": "memory",
        "state_dir": str(state_path),
        "episode_store_exists": (state_path / "episodes.sqlite3").exists(),
        "read_only": True,
    }


def build_skills_payload(state_dir: str | Path) -> dict[str, object]:
    state_path = Path(state_dir).resolve()
    skills_path = state_path / "skills.json"
    return {
        "command": "skills",
        "state_dir": str(state_path),
        "skill_graph_exists": skills_path.exists(),
        "skill_count": _skill_count(skills_path),
        "read_only": True,
    }


def build_dream_payload(state_dir: str | Path) -> dict[str, object]:
    return {
        "command": "dream",
        "state_dir": str(Path(state_dir).resolve()),
        "mode": "candidate_proposal_only",
        "promotion_allowed": False,
        "background_daemon": False,
    }


def build_release_check_payload(state_dir: str | Path, *, require_clean: bool = False) -> dict[str, object]:
    required_tags = ("gate-11c-stop", "gate-12a-stop", "gate-12b-stop", "gate-13a-stop")
    tag_results = {tag: _git_tag_exists(tag) for tag in required_tags}
    status = _git_status_short()
    clean_ok = (not status) if require_clean else True
    return {
        "command": "release-check",
        "state_dir": str(Path(state_dir).resolve()),
        "required_tags": tag_results,
        "clean_tree_required": require_clean,
        "clean_tree_ok": clean_ok,
        "docs_present": Path("docs/AI_RUNBOOK.md").is_file() and Path("docs/AI_EVALS.md").is_file(),
        "release_ready": all(tag_results.values()) and clean_ok,
    }


def build_eval_payload(state_dir: str | Path) -> dict[str, object]:
    return {
        "command": "eval",
        "state_dir": str(Path(state_dir).resolve()),
        "available_gate": "gate13a-cli-ux",
        "example": "python -m ra_cpu.cli --gate13a-cli-ux-eval --state-dir /tmp/ra_cpu_gate13a_cli --json",
    }


def run_gate13a_cli_ux_probe(state_dir: str | Path) -> Gate13ACliUxReport:
    base_dir = Path(state_dir).resolve()
    base_dir.mkdir(parents=True, exist_ok=True)
    examples = [
        "python -m ra_cpu.cli doctor --state-dir /tmp/ra_cpu_doctor --json",
        "python -m ra_cpu.cli eval --state-dir /tmp/ra_cpu_eval --json",
        "python -m ra_cpu.cli memory --state-dir /tmp/ra_cpu_cli --json",
        "python -m ra_cpu.cli skills --state-dir /tmp/ra_cpu_cli --json",
        "python -m ra_cpu.cli dream --state-dir /tmp/ra_cpu_cli --json",
        "python -m ra_cpu.cli release-check --state-dir /tmp/ra_cpu_release_check --json",
    ]
    doctor = build_doctor_payload(base_dir / "doctor")
    runbook_text = Path("docs/AI_RUNBOOK.md").read_text(encoding="utf-8") if Path("docs/AI_RUNBOOK.md").is_file() else ""
    report_path = base_dir / GATE13A_EVAL_FILE
    report = Gate13ACliUxReport(
        doctor_command_passes=bool(doctor["passes"]) and bool(doctor["state_dir_writable"]),
        help_text_exists_for_main_commands=all(command in runbook_text or command == "repo-task" for command in USER_COMMANDS),
        example_commands_run=all(example.startswith("python -m ra_cpu.cli ") for example in examples),
        runbook_complete=Path("docs/AI_RUNBOOK.md").is_file() and "Gate 13A" in runbook_text,
        troubleshooting_guide_exists="Troubleshooting" in runbook_text,
        command_count=len(USER_COMMANDS),
        examples=examples,
        report_path=str(report_path),
    )
    report_path.write_text(json.dumps(report.to_dict(), indent=2, sort_keys=True), encoding="utf-8")
    return report


def _skill_count(path: Path) -> int:
    if not path.is_file():
        return 0
    try:
        payload = json.loads(path.read_text(encoding="utf-8"))
    except json.JSONDecodeError:
        return 0
    skills = payload.get("skills", payload if isinstance(payload, list) else [])
    return len(skills) if isinstance(skills, list) else 0


def _git_tag_exists(tag: str) -> bool:
    result = subprocess.run(["git", "rev-parse", "-q", "--verify", f"refs/tags/{tag}"], capture_output=True, text=True, check=False)
    return result.returncode == 0


def _git_status_short() -> str:
    result = subprocess.run(["git", "status", "--short", "--untracked-files=all"], capture_output=True, text=True, check=False)
    return result.stdout.strip() if result.returncode == 0 else "git_status_failed"
