"""CLI entry point for Staso tooling.

Usage:
    staso setup-claude-code --api-key ak_... [options]
"""
from __future__ import annotations

import argparse
import json
import os
import sys
from pathlib import Path


# ── setup-claude-code ─────────────────────────────────────────────────────────

_HOOK_EVENTS_WITH_MATCHER = ("PostToolUse", "PostToolUseFailure")
_HOOK_EVENTS = (
    "SessionStart",
    "UserPromptSubmit",
    "PostToolUse",
    "PostToolUseFailure",
    "Stop",
    "SubagentStop",
    "SessionEnd",
)


def _hook_entry(command: str, with_matcher: bool = False) -> dict:
    hook: dict = {"type": "command", "command": command}
    if with_matcher:
        return {"matcher": ".*", "hooks": [hook]}
    return {"hooks": [hook]}


def _build_hooks_config(command: str) -> dict:
    hooks: dict = {}
    for event in _HOOK_EVENTS:
        hooks[event] = [_hook_entry(command, with_matcher=event in _HOOK_EVENTS_WITH_MATCHER)]
    return hooks


def _merge_settings(existing: dict, new_hooks: dict, new_env: dict) -> dict:
    """Merge hook and env entries into existing settings, preserving unrelated keys."""
    result = dict(existing)

    existing_hooks = result.get("hooks", {})
    for event, entries in new_hooks.items():
        # Avoid duplicates: remove any existing Staso hook entries for this event
        current = [
            e for e in existing_hooks.get(event, [])
            if not _is_staso_hook(e)
        ]
        current.extend(entries)
        existing_hooks[event] = current
    result["hooks"] = existing_hooks

    existing_env = result.get("env", {})
    existing_env.update(new_env)
    result["env"] = existing_env

    return result


def _is_staso_hook(entry: dict) -> bool:
    """Return True if this hook entry was written by Staso setup."""
    if "hooks" in entry:
        return any("staso.claude_code" in h.get("command", "") for h in entry.get("hooks", []))
    return "staso.claude_code" in entry.get("command", "")


def cmd_setup_claude_code(args: argparse.Namespace) -> int:
    """Write Claude Code hook configuration to the chosen settings file."""
    # Resolve API key
    api_key = args.api_key or os.environ.get("STASO_API_KEY", "")
    if not api_key:
        print(
            "error: --api-key is required (or set STASO_API_KEY env var)",
            file=sys.stderr,
        )
        return 1

    # Use the Python interpreter that's running this command
    python = sys.executable
    command = f"{python} -m staso.claude_code"

    hooks = _build_hooks_config(command)
    env_vars: dict[str, str] = {"STASO_API_KEY": api_key}
    if args.base_url:
        env_vars["STASO_BASE_URL"] = args.base_url
    if args.workspace:
        env_vars["STASO_WORKSPACE_SLUG"] = args.workspace
    if args.environment:
        env_vars["STASO_ENVIRONMENT"] = args.environment
    if args.agent_id:
        env_vars["STASO_AGENT_ID"] = args.agent_id

    # Determine settings file path
    if args.scope == "global":
        settings_path = Path.home() / ".claude" / "settings.json"
    else:
        settings_path = Path(".claude") / "settings.local.json"

    # Read existing settings
    settings_path.parent.mkdir(parents=True, exist_ok=True)
    existing: dict = {}
    if settings_path.exists():
        try:
            existing = json.loads(settings_path.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, OSError):
            print(
                f"warning: could not read existing {settings_path}, starting fresh",
                file=sys.stderr,
            )

    merged = _merge_settings(existing, hooks, env_vars)
    settings_path.write_text(json.dumps(merged, indent=2), encoding="utf-8")

    scope_label = "~/.claude/settings.json" if args.scope == "global" else ".claude/settings.local.json"
    print(f"Staso Claude Code hooks configured in {scope_label}")
    print(f"  Python: {python}")
    print(f"  API key: {api_key[:8]}...")
    if args.base_url:
        print(f"  Backend: {args.base_url}")
    print()
    print("Start a Claude Code session to begin tracing.")
    return 0


# ── main ──────────────────────────────────────────────────────────────────────

def _build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="staso",
        description="Staso CLI",
    )
    sub = parser.add_subparsers(dest="command")

    setup = sub.add_parser(
        "setup-claude-code",
        help="Configure Claude Code hooks to send traces to Staso",
    )
    setup.add_argument("--api-key", metavar="KEY", help="Staso API key (ak_...)")
    setup.add_argument("--base-url", metavar="URL", help="Staso backend URL")
    setup.add_argument("--workspace", metavar="SLUG", help="Workspace slug")
    setup.add_argument("--environment", metavar="ENV", default="production", help="Environment name (default: production)")
    setup.add_argument("--agent-id", metavar="ID", help="Agent ID registered in Staso")
    setup.add_argument(
        "--scope",
        choices=["global", "project"],
        default="global",
        help="Write to ~/.claude/settings.json (global) or .claude/settings.local.json (project)",
    )
    return parser


def main() -> None:
    parser = _build_parser()
    args = parser.parse_args()

    if args.command == "setup-claude-code":
        sys.exit(cmd_setup_claude_code(args))
    else:
        parser.print_help()
        sys.exit(0)
