#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import os
import shlex
from pathlib import Path
from typing import Any


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Install the dxcli portable Codex Stop hook into hooks.json")
    parser.add_argument(
        "--codex-dir",
        default=os.path.expanduser("~/.codex"),
        help="Codex config directory, default ~/.codex",
    )
    parser.add_argument(
        "--hook-script",
        default=str(Path(__file__).resolve().parents[1] / "dxcli_codex_hook.py"),
        help="Absolute path to dxcli_codex_hook.py",
    )
    parser.add_argument(
        "--timeout",
        type=int,
        default=15,
        help="Hook command timeout in seconds",
    )
    parser.add_argument(
        "--portable-config-path",
        default="",
        help="Path to portable_config.json exported for the hook command",
    )
    parser.add_argument(
        "--hook-spool-path",
        default="",
        help="Path to failed Telegram delivery spool exported for the hook command",
    )
    return parser.parse_args()


def load_hooks_file(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {"hooks": {}}
    try:
        loaded = json.loads(path.read_text(encoding="utf-8"))
    except json.JSONDecodeError:
        return {"hooks": {}}
    if not isinstance(loaded, dict):
        return {"hooks": {}}
    hooks = loaded.get("hooks")
    if not isinstance(hooks, dict):
        loaded["hooks"] = {}
    return loaded


def update_codex_config_features(codex_dir: Path) -> Path:
    config_path = codex_dir / "config.toml"
    text = config_path.read_text(encoding="utf-8") if config_path.exists() else ""
    lines = text.splitlines()
    output: list[str] = []
    in_features = False
    saw_features = False
    saw_hooks = False

    for line in lines:
        stripped = line.strip()
        if stripped.startswith("[") and stripped.endswith("]"):
            if in_features and not saw_hooks:
                output.append("hooks = true")
                saw_hooks = True
            in_features = stripped == "[features]"
            saw_features = saw_features or in_features
            output.append(line)
            continue
        if in_features:
            key = stripped.split("=", 1)[0].strip() if "=" in stripped else ""
            if key == "codex_hooks":
                continue
            if key == "hooks":
                output.append("hooks = true")
                saw_hooks = True
                continue
        output.append(line)

    if in_features and not saw_hooks:
        output.append("hooks = true")
        saw_hooks = True
    if not saw_features:
        if output and output[-1].strip():
            output.append("")
        output.extend(["[features]", "hooks = true"])

    config_path.write_text("\n".join(output).rstrip() + "\n", encoding="utf-8")
    return config_path


def main() -> int:
    args = parse_args()
    codex_dir = Path(args.codex_dir).expanduser().resolve()
    codex_dir.mkdir(parents=True, exist_ok=True)
    hooks_path = codex_dir / "hooks.json"
    hook_script = Path(args.hook_script).expanduser().resolve()
    if not hook_script.exists():
        raise SystemExit(f"hook script not found: {hook_script}")

    data = load_hooks_file(hooks_path)
    stop_groups = data.setdefault("hooks", {}).setdefault("Stop", [])
    if not isinstance(stop_groups, list):
        stop_groups = []
        data["hooks"]["Stop"] = stop_groups

    env_parts: list[str] = []
    if args.portable_config_path:
        env_parts.append(f"DXCLI_PORTABLE_CONFIG_PATH={shlex.quote(str(Path(args.portable_config_path).expanduser()))}")
    if args.hook_spool_path:
        env_parts.append(f"DXCLI_HOOK_SPOOL_PATH={shlex.quote(str(Path(args.hook_spool_path).expanduser()))}")
    command = " ".join([*env_parts, "python3", shlex.quote(str(hook_script))])
    normalized_groups: list[dict[str, Any]] = []
    seen_commands: set[str] = set()
    for group in stop_groups:
        if not isinstance(group, dict):
            continue
        hooks = group.get("hooks", [])
        if not isinstance(hooks, list):
            continue
        kept_hooks: list[dict[str, Any]] = []
        for hook in hooks:
            if not isinstance(hook, dict):
                continue
            hook_command = str(hook.get("command") or "")
            is_dxcli_hook = hook.get("type") == "command" and "dxcli_codex_hook.py" in hook_command
            if is_dxcli_hook:
                if hook_command in seen_commands or hook_command != command:
                    continue
                seen_commands.add(hook_command)
            kept_hooks.append(hook)
        if kept_hooks:
            normalized = dict(group)
            normalized["hooks"] = kept_hooks
            normalized_groups.append(normalized)
    stop_groups[:] = normalized_groups

    if command not in seen_commands:
        stop_groups.append(
            {
                "hooks": [
                    {
                        "type": "command",
                        "command": command,
                        "timeout": max(args.timeout, 1),
                        "statusMessage": "sending dxcli portable completion notice",
                    }
                ]
            }
        )

    hooks_path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
    config_path = update_codex_config_features(codex_dir)
    print(f"installed dxcli portable codex hook in {hooks_path}")
    print(f"enabled Codex hooks feature in {config_path}")
    return 0


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