"""``tribunal init`` — interactive project configuration wizard.

Prompts the user for Tribunal settings, writes a project-level config file,
and optionally syncs hooks into ``.claude/settings.json``.

Supports ``--non-interactive`` mode for CI environments.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path
from typing import NamedTuple

# Config file written into the project's .claude/ directory
_PROJECT_CONFIG_NAME = "tribunal.json"

# Sensible defaults used in non-interactive / CI mode
_DEFAULTS: dict = {
    "language": "Other",
    "tdd": "advisory",
    "secrets": True,
    "spec_workflow": True,
    "context_monitor": True,
}


class WizardConfig(NamedTuple):
    language: str
    tdd: str           # "strict" | "advisory" | "off"
    secrets: bool
    spec_workflow: bool
    context_monitor: bool


# ── helpers ───────────────────────────────────────────────────────────────────

def _prompt_choice(question: str, options: list[str], default_idx: int = 0) -> str:
    """Print numbered choices and return the selected option string."""
    print(f"\n  {question}")
    for i, opt in enumerate(options, 1):
        marker = " (default)" if i - 1 == default_idx else ""
        print(f"    [{i}] {opt}{marker}")

    while True:
        raw = input("  → ").strip()
        if raw == "":
            return options[default_idx]
        try:
            idx = int(raw) - 1
            if 0 <= idx < len(options):
                return options[idx]
        except ValueError:
            pass
        print(f"  Please enter a number between 1 and {len(options)}.")


def _prompt_yn(question: str, default: bool = True) -> bool:
    """Ask a yes/no question and return bool."""
    hint = "[Y/n]" if default else "[y/N]"
    raw = input(f"\n  {question} {hint}: ").strip().lower()
    if raw == "":
        return default
    return raw in ("y", "yes")


def _build_config(non_interactive: bool) -> WizardConfig:
    """Gather wizard answers — interactively or from defaults."""
    if non_interactive:
        return WizardConfig(**_DEFAULTS)

    print("\n  ╔══════════════════════════════════════════╗")
    print("  ║   Tribunal Init — Project Setup Wizard   ║")
    print("  ╚══════════════════════════════════════════╝")

    language = _prompt_choice(
        "Primary language?",
        ["Python", "TypeScript", "Go", "Other"],
        default_idx=0,
    )

    tdd_label = _prompt_choice(
        "TDD enforcement level?",
        [
            "Strict  — block writes when no failing test exists",
            "Advisory — show reminder only (non-blocking)",
            "Off     — disable TDD checks",
        ],
        default_idx=1,
    )
    tdd = {"Strict": "strict", "Advisory": "advisory", "Off": "off"}[tdd_label.split()[0]]

    secrets = _prompt_yn("Enable secret scanning?", default=True)
    spec_workflow = _prompt_yn("Enable spec workflow?", default=True)
    context_monitor = _prompt_yn("Enable context monitor?", default=True)

    return WizardConfig(
        language=language,
        tdd=tdd,
        secrets=secrets,
        spec_workflow=spec_workflow,
        context_monitor=context_monitor,
    )


def _write_project_config(config: WizardConfig, project_dir: Path) -> Path:
    """Write ``tribunal.json`` under ``{project_dir}/.claude/``."""
    claude_dir = project_dir / ".claude"
    claude_dir.mkdir(parents=True, exist_ok=True)
    config_path = claude_dir / _PROJECT_CONFIG_NAME

    data = {
        "language": config.language,
        "tdd": config.tdd,
        "secrets": config.secrets,
        "spec_workflow": config.spec_workflow,
        "context_monitor": config.context_monitor,
    }
    config_path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
    return config_path


def _ensure_claude_settings(project_dir: Path, config: WizardConfig) -> Path | None:
    """Merge Tribunal hook entries into ``.claude/settings.json`` in project_dir.

    Returns the settings path if updated, or None if unchanged.
    """
    settings_path = project_dir / ".claude" / "settings.json"

    # Ensure .claude/ exists
    claude_dir = project_dir / ".claude"
    claude_dir.mkdir(parents=True, exist_ok=True)

    # Load existing settings or start fresh
    existing: dict = {}
    if settings_path.exists():
        try:
            existing = json.loads(settings_path.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, OSError):
            existing = {}

    # Inject relevant Tribunal env vars based on config choices
    env: dict = existing.get("env", {})

    if config.tdd == "off":
        env["TRIBUNAL_TDD_DISABLED"] = "true"
    else:
        env.pop("TRIBUNAL_TDD_DISABLED", None)

    if config.tdd == "strict":
        env["TRIBUNAL_TDD_STRICT"] = "true"
    else:
        env.pop("TRIBUNAL_TDD_STRICT", None)

    if not config.secrets:
        env["TRIBUNAL_SECRETS_DISABLED"] = "true"
    else:
        env.pop("TRIBUNAL_SECRETS_DISABLED", None)

    if not config.spec_workflow:
        env["TRIBUNAL_SPEC_DISABLED"] = "true"
    else:
        env.pop("TRIBUNAL_SPEC_DISABLED", None)

    if not config.context_monitor:
        env["TRIBUNAL_CONTEXT_MONITOR_DISABLED"] = "true"
    else:
        env.pop("TRIBUNAL_CONTEXT_MONITOR_DISABLED", None)

    if env:
        existing["env"] = env
    elif "env" in existing and not existing["env"]:
        del existing["env"]

    try:
        settings_path.write_text(json.dumps(existing, indent=2) + "\n", encoding="utf-8")
        return settings_path
    except OSError as exc:
        print(f"  Warning: could not write .claude/settings.json — {exc}", file=sys.stderr)
        return None


def _print_success(config_path: Path, settings_path: Path | None, config: WizardConfig) -> None:
    """Print a friendly success banner with next steps."""
    print("\n  ╔══════════════════════════════════════════╗")
    print("  ║   ✅  Tribunal initialised successfully!  ║")
    print("  ╚══════════════════════════════════════════╝")
    print(f"\n  Config written to: {config_path}")
    if settings_path:
        print(f"  Claude settings:   {settings_path}")

    print("\n  Summary:")
    print(f"    Language       : {config.language}")
    tdd_labels = {"strict": "Strict (blocking)", "advisory": "Advisory (warn)", "off": "Off"}
    print(f"    TDD            : {tdd_labels.get(config.tdd, config.tdd)}")
    print(f"    Secret scanning: {'On' if config.secrets else 'Off'}")
    print(f"    Spec workflow  : {'On' if config.spec_workflow else 'Off'}")
    print(f"    Context monitor: {'On' if config.context_monitor else 'Off'}")

    print("\n  Next steps:")
    print("    1. Run  tribunal launch  to start a Tribunal-powered Claude session")
    print("    2. Run  tribunal status  to verify hook configuration")
    print("    3. Run  tribunal repair  if hooks are missing from ~/.claude/settings.json")
    print()


# ── public API ────────────────────────────────────────────────────────────────

def run_init_wizard(project_dir: Path | None = None, non_interactive: bool = False) -> None:
    """Entry point for ``tribunal init``.

    Args:
        project_dir: Root directory to initialise (defaults to cwd).
        non_interactive: Skip prompts and use sensible CI defaults.
    """
    base = project_dir or Path.cwd()

    try:
        config = _build_config(non_interactive)
    except (KeyboardInterrupt, EOFError):
        print("\n  Aborted.", file=sys.stderr)
        sys.exit(0)

    config_path = _write_project_config(config, base)
    settings_path = _ensure_claude_settings(base, config)
    _print_success(config_path, settings_path, config)
