# ClawTex — Governed Agent with Genetic Memory
# Built by DeVere Cooley / AN2B LLC · an2b.com
# BB4C — Breath Before Code

"""
ClawTex setup wizard — interactive first-run configuration.

Usage:
    clawtex setup
"""

from __future__ import annotations

import os
import sys
from pathlib import Path

ENV_PATH = Path(".env")
ENV_EXAMPLE_PATH = Path(".env.example")

BLUE  = "\033[0;34m"
GREEN = "\033[0;32m"
YELLOW = "\033[1;33m"
BOLD  = "\033[1m"
NC    = "\033[0m"


def banner():
    print(f"""
{BLUE}  ██████╗██╗      █████╗ ██╗    ██╗████████╗███████╗██╗  ██╗
 ██╔════╝██║     ██╔══██╗██║    ██║╚══██╔══╝██╔════╝╚██╗██╔╝
 ██║     ██║     ███████║██║ █╗ ██║   ██║   █████╗   ╚███╔╝
 ██║     ██║     ██╔══██║██║███╗██║   ██║   ██╔══╝   ██╔██╗
 ╚██████╗███████╗██║  ██║╚███╔███╔╝   ██║   ███████╗██╔╝ ██╗
  ╚═════╝╚══════╝╚═╝  ╚═╝ ╚══╝╚══╝    ╚═╝   ╚══════╝╚═╝  ╚═╝{NC}

  {BOLD}Governed Agent · Genetic Memory · BB4C{NC}
  Built by DeVere Cooley / AN2B LLC · an2b.com
""")


def ask(prompt: str, default: str = "", secret: bool = False) -> str:
    display = f"  {BOLD}{prompt}{NC}"
    if default:
        display += f" [{default}]"
    display += ": "
    try:
        if secret:
            import getpass
            val = getpass.getpass(display)
        else:
            val = input(display).strip()
        return val if val else default
    except (EOFError, KeyboardInterrupt):
        print("\n\n  Setup cancelled.")
        sys.exit(0)


def ask_choice(prompt: str, choices: list[str], default: str) -> str:
    options = "/".join(f"{BOLD}{c}{NC}" if c == default else c for c in choices)
    result = ask(f"{prompt} ({options})", default=default)
    if result not in choices:
        return default
    return result


def ok(msg: str):
    print(f"  {GREEN}✓{NC}  {msg}")


def warn(msg: str):
    print(f"  {YELLOW}!{NC}  {msg}")


def run_wizard() -> None:
    banner()
    print(f"  {BOLD}Welcome to ClawTex setup.{NC}")
    print("  This wizard will configure your agent in under 2 minutes.\n")

    config: dict[str, str] = {}

    # ── Identity ────────────────────────────────────────────────────
    print(f"\n  {BLUE}── Identity{NC}")
    config["CLAWTEX_NAME"] = ask("Agent name", default="ClawTex")
    config["CLAWTEX_SOUL"] = ask("Path to SOUL.md", default="./SOUL.md")

    # ── LLM Provider ────────────────────────────────────────────────
    print(f"\n  {BLUE}── LLM Provider{NC}")
    provider = ask_choice("Provider", ["anthropic", "openai"], default="anthropic")
    config["LLM_PROVIDER"] = provider

    if provider == "anthropic":
        config["ANTHROPIC_API_KEY"] = ask("Anthropic API key (sk-ant-...)", secret=True)
    else:
        config["OPENAI_API_KEY"] = ask("OpenAI API key (sk-...)", secret=True)
        config["OPENAI_MODEL"] = ask("Model", default="gpt-4o")

    # ── Memory (MandelDB) ────────────────────────────────────────────
    print(f"\n  {BLUE}── Memory (MandelDB){NC}")
    print("  Get a free bot key at https://mandeldb.com")
    mandeldb_key = ask("MandelDB API key (ek_bot_...)", secret=True)
    config["MANDELDB_API_KEY"] = mandeldb_key
    config["MANDELDB_URL"] = ask("MandelDB URL", default="https://mandeldb.com")

    # ── Channels ─────────────────────────────────────────────────────
    print(f"\n  {BLUE}── Channels{NC}")
    print("  Configure at least one channel (press Enter to skip).")

    tg = ask("Telegram bot token (xoxb-... or skip)")
    if tg:
        config["TELEGRAM_BOT_TOKEN"] = tg

    sl = ask("Slack bot token (xoxb-... or skip)")
    if sl:
        config["SLACK_BOT_TOKEN"] = sl
        config["SLACK_APP_TOKEN"] = ask("Slack app token (xapp-...)")

    if not tg and not sl:
        warn("No channels configured — agent will run in CLI mode only.")

    # ── Governance ───────────────────────────────────────────────────
    print(f"\n  {BLUE}── Governance{NC}")
    warden_mode = ask_choice(
        "Warden mode",
        ["enforce", "audit", "off"],
        default="enforce",
    )
    config["WARDEN_MODE"] = warden_mode
    config["WARDEN_POLICY"] = "./clawtex/governance/policies/default.yaml"

    if warden_mode == "off":
        warn("Governance is OFF — all actions will execute without policy checks.")

    # ── Dream cycle ──────────────────────────────────────────────────
    config["DREAM_INTERVAL_HOURS"] = ask("Memory dream cycle (hours)", default="6")

    # ── Write .env ───────────────────────────────────────────────────
    print(f"\n  {BLUE}── Writing configuration{NC}")
    _write_env(config)
    ok(f".env written ({len(config)} values)")

    # ── Summary ──────────────────────────────────────────────────────
    print(f"""
  {GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{NC}
  {GREEN}  ClawTex is configured.  BB4C — Breath Before Code.{NC}
  {GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{NC}

  Start your agent:

    {BOLD}clawtex start{NC}

  Verify governance:

    {BOLD}clawtex check{NC}

  Docs: https://github.com/an2b-llc/clawtex
""")


def _write_env(config: dict[str, str]) -> None:
    """Write config to .env, preserving any existing values not in config."""
    existing: dict[str, str] = {}

    if ENV_PATH.exists():
        for line in ENV_PATH.read_text().splitlines():
            line = line.strip()
            if line and not line.startswith("#") and "=" in line:
                k, _, v = line.partition("=")
                existing[k.strip()] = v.strip()

    existing.update(config)

    lines = [
        "# ClawTex configuration",
        "# BB4C — Breath Before Code · AN2B LLC",
        "# Generated by: clawtex setup",
        "",
    ]

    sections = {
        "Identity": ["CLAWTEX_NAME", "CLAWTEX_SOUL"],
        "LLM Provider": ["LLM_PROVIDER", "ANTHROPIC_API_KEY", "OPENAI_API_KEY", "OPENAI_MODEL"],
        "Memory (MandelDB)": ["MANDELDB_URL", "MANDELDB_API_KEY"],
        "Channels": ["TELEGRAM_BOT_TOKEN", "SLACK_BOT_TOKEN", "SLACK_APP_TOKEN"],
        "Governance": ["WARDEN_POLICY", "WARDEN_MODE"],
        "Dream Cycle": ["DREAM_INTERVAL_HOURS"],
    }

    written: set[str] = set()
    for section, keys in sections.items():
        section_lines = []
        for key in keys:
            if key in existing:
                section_lines.append(f"{key}={existing[key]}")
                written.add(key)
        if section_lines:
            lines.append(f"# {section}")
            lines.extend(section_lines)
            lines.append("")

    # Any remaining keys not in sections
    remainder = [f"{k}={v}" for k, v in existing.items() if k not in written]
    if remainder:
        lines.append("# Other")
        lines.extend(remainder)
        lines.append("")

    ENV_PATH.write_text("\n".join(lines))
