"""One-command setup for host agent integration."""

import os
import platform
import secrets
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

import click
from rich.console import Console

console = Console()

_PLIST_LABEL = "com.primordial.daemon"
_PLIST_DIR = Path.home() / "Library" / "LaunchAgents"
_PLIST_PATH = _PLIST_DIR / f"{_PLIST_LABEL}.plist"
_IS_WINDOWS = platform.system() == "Windows"
_PASSWORD_FILE = Path.home() / ".primordial-password"
_TOKEN_FILE = Path.home() / ".primordial-daemon-token"
_WRAPPER_DIR = Path.home() / ".local" / "bin"
_WRAPPER_PATH = _WRAPPER_DIR / ("primordial.cmd" if _IS_WINDOWS else "primordial")
_LOG_PATH = Path(tempfile.gettempdir()) / "primordial-daemon.log"

# Skill file source (bundled inside the primordial package)
_SKILL_DIR = Path(__file__).resolve().parent.parent / "skills"

_OPENCLAW_SKILL_DEST = Path.home() / ".openclaw" / "workspace" / "skills" / "primordial"
_CLAUDE_SKILL_DEST = Path.home() / ".claude" / "skills" / "primordial"


def _find_real_binary() -> str:
    """Find the real primordial binary path."""
    which_cmd = "where" if _IS_WINDOWS else "which"
    path_sep = ";" if _IS_WINDOWS else ":"
    result = subprocess.run(
        [which_cmd, "primordial"], capture_output=True, text=True
    )
    path = result.stdout.strip().splitlines()[0] if result.stdout.strip() else ""
    if path and Path(path).exists():
        # If it's already our wrapper, find the pip-installed one
        if path == str(_WRAPPER_PATH):
            # Search PATH excluding our wrapper dir
            env = os.environ.copy()
            path_dirs = [
                d for d in env.get("PATH", "").split(path_sep)
                if d != str(_WRAPPER_DIR)
            ]
            env["PATH"] = path_sep.join(path_dirs)
            result = subprocess.run(
                [which_cmd, "primordial"], capture_output=True, text=True, env=env
            )
            return result.stdout.strip().splitlines()[0] if result.stdout.strip() else "primordial"
        return path
    return "primordial"


def _get_or_create_password() -> tuple[str, bool]:
    """Read existing vault password or generate a new one.

    Returns (password, created) where created is True if a new password was generated.
    """
    if _PASSWORD_FILE.exists():
        return _PASSWORD_FILE.read_text().strip(), False
    password = secrets.token_urlsafe(32)
    _PASSWORD_FILE.write_text(password)
    if platform.system() != "Windows":
        _PASSWORD_FILE.chmod(0o600)
    return password, True


def _create_wrapper(real_binary: str, password: str):
    """Create a wrapper script that sets vault password before exec.

    Skips if the wrapper already exists with the same binary path.
    """
    if _WRAPPER_PATH.exists():
        existing = _WRAPPER_PATH.read_text()
        if real_binary in existing and password in existing:
            return False  # No change needed

    _WRAPPER_DIR.mkdir(parents=True, exist_ok=True)
    if _IS_WINDOWS:
        script = f'@echo off\r\nset PRIMORDIAL_VAULT_PASSWORD={password}\r\n"{real_binary}" %*\r\n'
    else:
        script = f"""#!/bin/sh
export PRIMORDIAL_VAULT_PASSWORD='{password}'
exec "{real_binary}" "$@"
"""
    _WRAPPER_PATH.write_text(script)
    if not _IS_WINDOWS:
        _WRAPPER_PATH.chmod(0o700)
    return True


def _build_plist() -> str:
    """Build the plist XML content."""
    return f"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>{_PLIST_LABEL}</string>
  <key>ProgramArguments</key><array>
    <string>{_WRAPPER_PATH}</string>
    <string>serve</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardErrorPath</key><string>{_LOG_PATH}</string>
</dict>
</plist>
"""


def _create_plist():
    """Install launchd plist for auto-starting the daemon.

    Only reloads if the plist content actually changed.
    """
    _PLIST_DIR.mkdir(parents=True, exist_ok=True)
    new_content = _build_plist()

    if _PLIST_PATH.exists():
        existing = _PLIST_PATH.read_text()
        if existing == new_content:
            return False  # No change needed

        subprocess.run(
            ["launchctl", "unload", str(_PLIST_PATH)],
            capture_output=True,
        )

    _PLIST_PATH.write_text(new_content)
    subprocess.run(["launchctl", "load", str(_PLIST_PATH)], check=True)
    return True


def _install_skill(name: str, dest: Path, source_name: str):
    """Copy a skill file to the destination."""
    source = _SKILL_DIR / source_name
    if not source.exists():
        console.print(f"  [yellow]Skill file not found: {source_name}[/yellow]")
        return
    dest.mkdir(parents=True, exist_ok=True)
    shutil.copy2(source, dest / "SKILL.md")
    console.print(f"  [green]Installed {name} skill →[/green] {dest / 'SKILL.md'}")


def _prompt_e2b_key():
    """Check if e2b key exists in vault; prompt if missing."""
    from primordial.config import get_config
    from primordial.security.key_vault import KeyVault

    config = get_config()
    vault = KeyVault(config.keys_file)

    if vault.get_key("e2b"):
        console.print("  [dim]e2b key already configured.[/dim]")
        return

    console.print()
    console.print("  [bold]The E2B API key is required to run agents.[/bold]")
    console.print("  [dim]Get one free at https://e2b.dev/dashboard[/dim]")
    console.print()

    key = click.prompt(
        "  Paste your E2B API key (Enter to skip)",
        default="",
        show_default=False,
        hide_input=True,
    ).strip()

    if key:
        vault.add_key("e2b", key)
        console.print("  [green]Stored e2b key.[/green]")
    else:
        console.print("  [yellow]Skipped. Run 'primordial setup' later to add it.[/yellow]")


@click.command()
@click.option("--openclaw", is_flag=True, help="Install for OpenClaw")
@click.option("--claude", is_flag=True, help="Install for Claude Code")
@click.option("--codex", is_flag=True, help="Install for Codex CLI")
@click.option("--all", "install_all", is_flag=True, help="Install for all hosts")
def install(openclaw: bool, claude: bool, codex: bool, install_all: bool):
    """Install Primordial for host agent integration.

    Sets up vault password, wrapper script, launchd daemon, and skill files.
    Safe to run multiple times — won't destroy existing keys or config.
    """
    if not any([openclaw, claude, codex, install_all]):
        console.print("[yellow]Specify a target: --openclaw, --claude, --codex, or --all[/yellow]")
        raise SystemExit(1)

    if install_all:
        openclaw = claude = codex = True

    real_binary = _find_real_binary()
    console.print(f"[dim]Found primordial at: {real_binary}[/dim]")

    # 1. Vault password (idempotent)
    console.print("\n[bold]1.[/bold] Vault password...")
    password, created = _get_or_create_password()
    if created:
        console.print(f"  [green]Generated →[/green] {_PASSWORD_FILE}")
    else:
        console.print(f"  [dim]Already exists →[/dim] {_PASSWORD_FILE}")

    # 2. Wrapper script (idempotent)
    console.print("[bold]2.[/bold] Wrapper script...")
    changed = _create_wrapper(real_binary, password)
    if changed:
        console.print(f"  [green]Created →[/green] {_WRAPPER_PATH}")
    else:
        console.print(f"  [dim]Already up to date →[/dim] {_WRAPPER_PATH}")

    # 3. Launchd daemon (idempotent)
    if sys.platform == "darwin":
        console.print("[bold]3.[/bold] Launchd daemon...")
        changed = _create_plist()
        if changed:
            console.print(f"  [green]Loaded →[/green] {_PLIST_PATH}")
        else:
            console.print(f"  [dim]Already up to date →[/dim] {_PLIST_PATH}")
    else:
        console.print("[bold]3.[/bold] [dim]Skipping launchd (not macOS)[/dim]")

    # 4. Skill files
    console.print("[bold]4.[/bold] Installing skill files...")
    if openclaw:
        _install_skill("OpenClaw", _OPENCLAW_SKILL_DEST, "SKILL-openclaw.md")
    if claude:
        _install_skill("Claude Code", _CLAUDE_SKILL_DEST, "SKILL-claude.md")
    if codex:
        codex_dest = Path.home() / ".codex"
        codex_dest.mkdir(parents=True, exist_ok=True)
        source = _SKILL_DIR / "SKILL-codex.md"
        if source.exists():
            # Append to AGENTS.md
            agents_md = codex_dest / "AGENTS.md"
            content = source.read_text()
            if agents_md.exists():
                existing = agents_md.read_text()
                if "Primordial AgentStore" not in existing:
                    agents_md.write_text(existing + "\n\n" + content)
                    console.print(f"  [green]Appended Codex skill →[/green] {agents_md}")
                else:
                    console.print(f"  [dim]Codex skill already present in {agents_md}[/dim]")
            else:
                agents_md.write_text(content)
                console.print(f"  [green]Created Codex skill →[/green] {agents_md}")
        else:
            console.print(f"  [yellow]Skill file not found: SKILL-codex.md[/yellow]")

    # 5. E2B key prompt
    console.print("[bold]5.[/bold] Checking API keys...")
    _prompt_e2b_key()

    console.print(f"\n[bold green]Done![/bold green] Primordial is ready.")
    console.print(f"[dim]Daemon log: {_LOG_PATH}[/dim]")
