#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════════════════════
# Echo Core — Interactive Setup Wizard
# Re-run safe: detects existing venv, config, secrets. Backs up before writing.
# ═══════════════════════════════════════════════════════════════════════════════

set -uo pipefail

# ---------------------------------------------------------------------------
# Globals
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="$SCRIPT_DIR/config.json"
META_FILE="$SCRIPT_DIR/.setup-meta.json"
VENV_DIR="$SCRIPT_DIR/.venv"
REQUIREMENTS="$SCRIPT_DIR/requirements.txt"
WA_BRIDGE_DIR="$SCRIPT_DIR/bridge/whatsapp"
SYSTEMD_DIR="$HOME/.config/systemd/user"
KEYRING_SERVICE="echo-core"

# State collected during wizard
BOT_NAME=""
OWNER_DISCORD_ID=""
ADMIN_IDS=""
DISCORD_ENABLED=false
DISCORD_TOKEN=""
DISCORD_CHANNEL_ID=""
DISCORD_CHANNEL_ALIAS=""
TELEGRAM_ENABLED=false
TELEGRAM_TOKEN=""
TELEGRAM_ADMIN_IDS=""
WHATSAPP_ENABLED=false
WHATSAPP_OWNER_PHONE=""
NODE_AVAILABLE=false
SERVICES_INSTALLED=false
START_NOW=false
CURRENT_STEP=0

# Prereq results
HAS_PYTHON=false
HAS_PIP=false
HAS_NODE=false
HAS_CLAUDE=false
HAS_CURL=false
HAS_SYSTEMCTL=false
PYTHON_BIN=""

# ---------------------------------------------------------------------------
# Colors & UI
# ---------------------------------------------------------------------------
if [[ -t 1 ]]; then
    C_RESET='\033[0m'
    C_BOLD='\033[1m'
    C_DIM='\033[2m'
    C_ORANGE='\033[38;5;208m'
    C_GREEN='\033[38;5;82m'
    C_RED='\033[38;5;196m'
    C_YELLOW='\033[38;5;220m'
    C_CYAN='\033[38;5;45m'
    C_GRAY='\033[38;5;245m'
else
    C_RESET='' C_BOLD='' C_DIM='' C_ORANGE='' C_GREEN=''
    C_RED='' C_YELLOW='' C_CYAN='' C_GRAY=''
fi

info()    { echo -e "${C_GRAY}  $*${C_RESET}"; }
success() { echo -e "${C_GREEN}  ✓ $*${C_RESET}"; }
warn()    { echo -e "${C_YELLOW}  ⚠ $*${C_RESET}"; }
error()   { echo -e "${C_RED}  ✗ $*${C_RESET}"; }
accent()  { echo -e "${C_ORANGE}$*${C_RESET}"; }
dim()     { echo -e "${C_DIM}$*${C_RESET}"; }

# Box header for each step
step_header() {
    local num="$1" title="$2"
    echo ""
    echo -e "${C_ORANGE}┌──────────────────────────────────────────────────────────┐${C_RESET}"
    echo -e "${C_ORANGE}│${C_RESET} ${C_BOLD}Step $num: $title${C_RESET}"
    echo -e "${C_ORANGE}└──────────────────────────────────────────────────────────┘${C_RESET}"
}

# Braille spinner
spinner() {
    local pid=$1 msg="$2"
    local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
    local i=0
    while kill -0 "$pid" 2>/dev/null; do
        printf "\r  ${C_CYAN}%s${C_RESET} %s" "${frames[$i]}" "$msg"
        i=$(( (i + 1) % ${#frames[@]} ))
        sleep 0.1
    done
    printf "\r\033[K"
}

# Prompt with default — returns answer in $REPLY
ask() {
    local prompt="$1" default="${2:-}"
    if [[ -n "$default" ]]; then
        printf "  ${C_ORANGE}▸${C_RESET} %s [${C_DIM}%s${C_RESET}]: " "$prompt" "$default"
    else
        printf "  ${C_ORANGE}▸${C_RESET} %s: " "$prompt"
    fi
    read -r REPLY
    [[ -z "$REPLY" ]] && REPLY="$default"
}

# Yes/no prompt — sets REPLY to y or n
ask_yn() {
    local prompt="$1" default="${2:-y}"
    local hint="Y/n"
    [[ "$default" == "n" ]] && hint="y/N"
    printf "  ${C_ORANGE}▸${C_RESET} %s [%s]: " "$prompt" "$hint"
    read -r REPLY
    REPLY="${REPLY:-$default}"
    REPLY="${REPLY,,}"  # lowercase
    [[ "$REPLY" == y* ]] && REPLY="y" || REPLY="n"
}

# Secret input (masked)
ask_secret() {
    local prompt="$1"
    printf "  ${C_ORANGE}▸${C_RESET} %s: " "$prompt"
    read -rs REPLY
    echo ""
}

# ---------------------------------------------------------------------------
# Ctrl+C handler
# ---------------------------------------------------------------------------
cleanup() {
    echo ""
    echo -e "${C_YELLOW}Setup interrupted at step $CURRENT_STEP. Re-run anytime to continue.${C_RESET}"
    exit 130
}
trap cleanup INT

# Step failure handler — offers to continue
step_failed() {
    local step_name="$1"
    error "$step_name failed"
    ask_yn "Continue with remaining steps?" "y"
    [[ "$REPLY" == "n" ]] && exit 1
}

# ---------------------------------------------------------------------------
# Step 0: Welcome
# ---------------------------------------------------------------------------
step_welcome() {
    CURRENT_STEP=0
    echo ""
    echo -e "${C_ORANGE}${C_BOLD}"
    cat << 'LOGO'
    ███████╗ ██████╗██╗  ██╗ ██████╗
    ██╔════╝██╔════╝██║  ██║██╔═══██╗
    █████╗  ██║     ███████║██║   ██║
    ██╔══╝  ██║     ██╔══██║██║   ██║
    ███████╗╚██████╗██║  ██║╚██████╔╝
    ╚══════╝ ╚═════╝╚═╝  ╚═╝ ╚═════╝
LOGO
    echo -e "${C_RESET}"
    echo -e "  ${C_BOLD}Echo Core — Interactive Setup Wizard${C_RESET}"

    # Show version from HANDOFF.md or git
    if command -v git &>/dev/null && git -C "$SCRIPT_DIR" rev-parse --short HEAD &>/dev/null 2>&1; then
        local ver
        ver=$(git -C "$SCRIPT_DIR" rev-parse --short HEAD 2>/dev/null)
        dim "  Version: git@$ver"
    fi
    echo ""

    # Detect previous setup
    if [[ -f "$META_FILE" ]]; then
        local prev_date
        prev_date=$(python3 -c "import json; print(json.load(open('$META_FILE')).get('date','unknown'))" 2>/dev/null || echo "unknown")
        warn "Previous setup detected (from $prev_date)"
        info "Existing config and secrets will be preserved unless you choose to replace them."
        echo ""
    fi

    if [[ -f "$CONFIG_FILE" ]]; then
        info "Existing config.json found — will merge, not overwrite."
    fi

    echo -e "  ${C_DIM}This wizard will guide you through configuring Echo Core.${C_RESET}"
    echo -e "  ${C_DIM}Press Ctrl+C at any time to abort.${C_RESET}"
    echo ""
    ask_yn "Ready to begin?" "y"
    [[ "$REPLY" == "n" ]] && { echo "  Aborted."; exit 0; }
}

# ---------------------------------------------------------------------------
# Step 1: Prerequisites
# ---------------------------------------------------------------------------
step_prerequisites() {
    CURRENT_STEP=1
    step_header 1 "Prerequisites Check"

    local fail=false

    # Python 3.12+
    if command -v python3 &>/dev/null; then
        PYTHON_BIN="$(command -v python3)"
        local pyver
        pyver=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null)
        local major minor
        major=$(echo "$pyver" | cut -d. -f1)
        minor=$(echo "$pyver" | cut -d. -f2)
        if [[ "$major" -ge 3 && "$minor" -ge 12 ]]; then
            success "Python $pyver ($PYTHON_BIN)"
            HAS_PYTHON=true
        else
            error "Python $pyver found — need 3.12+"
            fail=true
        fi
    else
        error "Python 3 not found"
        fail=true
    fi

    # pip
    if python3 -m pip --version &>/dev/null 2>&1; then
        success "pip $(python3 -m pip --version 2>/dev/null | awk '{print $2}')"
        HAS_PIP=true
    else
        error "pip not found (python3 -m pip)"
        fail=true
    fi

    # Node.js 22+ (warn only)
    if command -v node &>/dev/null; then
        local nodever
        nodever=$(node --version 2>/dev/null | sed 's/^v//')
        local nodemajor
        nodemajor=$(echo "$nodever" | cut -d. -f1)
        if [[ "$nodemajor" -ge 22 ]]; then
            success "Node.js v$nodever"
            HAS_NODE=true
            NODE_AVAILABLE=true
        else
            warn "Node.js v$nodever — need 22+ for WhatsApp bridge"
            NODE_AVAILABLE=false
        fi
    else
        warn "Node.js not found (needed only for WhatsApp bridge)"
        NODE_AVAILABLE=false
    fi

    # Claude CLI
    if command -v claude &>/dev/null; then
        success "Claude CLI found"
        HAS_CLAUDE=true
    else
        error "Claude CLI not found — required for bot operation"
        fail=true
    fi

    # curl (warn)
    if command -v curl &>/dev/null; then
        success "curl"
        HAS_CURL=true
    else
        warn "curl not found — token validation will be skipped"
    fi

    # systemctl (warn)
    if command -v systemctl &>/dev/null; then
        success "systemctl"
        HAS_SYSTEMCTL=true
    else
        warn "systemctl not found — service installation will be skipped"
    fi

    if $fail; then
        error "Required prerequisites missing. Install them and re-run."
        exit 1
    fi

    echo ""
    success "All required prerequisites OK"
}

# ---------------------------------------------------------------------------
# Step 2: Python Virtual Environment
# ---------------------------------------------------------------------------
step_venv() {
    CURRENT_STEP=2
    step_header 2 "Python Virtual Environment"

    if [[ -d "$VENV_DIR" && -f "$VENV_DIR/bin/python3" ]]; then
        success "Virtual environment exists at .venv/"
        ask_yn "Reinstall dependencies from requirements.txt?" "n"
        if [[ "$REPLY" == "n" ]]; then
            info "Skipping dependency installation."
            return 0
        fi
    else
        info "Creating virtual environment..."
        if ! python3 -m venv "$VENV_DIR" 2>/dev/null; then
            error "Failed to create venv"
            step_failed "Venv creation"
            return 1
        fi
        success "Created .venv/"
    fi

    if [[ ! -f "$REQUIREMENTS" ]]; then
        warn "requirements.txt not found — skipping pip install"
        return 0
    fi

    info "Installing dependencies..."
    "$VENV_DIR/bin/pip" install --upgrade pip -q &>/dev/null &
    spinner $! "Upgrading pip"
    success "pip upgraded"

    "$VENV_DIR/bin/pip" install -r "$REQUIREMENTS" -q &>/dev/null &
    spinner $! "Installing requirements"

    if "$VENV_DIR/bin/pip" install -r "$REQUIREMENTS" -q &>/dev/null; then
        success "Dependencies installed"
    else
        error "pip install failed"
        step_failed "Dependency installation"
    fi
}

# ---------------------------------------------------------------------------
# Step 3: Bot Identity
# ---------------------------------------------------------------------------
step_identity() {
    CURRENT_STEP=3
    step_header 3 "Bot Identity"

    # Read existing values from config
    local existing_name="" existing_owner="" existing_admins=""
    if [[ -f "$CONFIG_FILE" ]]; then
        existing_name=$("$VENV_DIR/bin/python3" -c "
import json
c = json.load(open('$CONFIG_FILE'))
print(c.get('bot',{}).get('name',''))" 2>/dev/null || echo "")
        existing_owner=$("$VENV_DIR/bin/python3" -c "
import json
c = json.load(open('$CONFIG_FILE'))
print(c.get('bot',{}).get('owner',''))" 2>/dev/null || echo "")
        existing_admins=$("$VENV_DIR/bin/python3" -c "
import json
c = json.load(open('$CONFIG_FILE'))
a = c.get('bot',{}).get('admins',[])
print(','.join(a))" 2>/dev/null || echo "")
    fi

    ask "Bot name" "${existing_name:-Echo}"
    BOT_NAME="$REPLY"

    ask "Owner Discord user ID" "$existing_owner"
    OWNER_DISCORD_ID="$REPLY"

    if [[ -n "$existing_admins" ]]; then
        info "Current admin IDs: $existing_admins"
    fi
    ask "Additional admin IDs (comma-separated, or blank)" "$existing_admins"
    ADMIN_IDS="$REPLY"

    echo ""
    success "Identity: ${C_BOLD}$BOT_NAME${C_RESET}${C_GREEN} (owner: $OWNER_DISCORD_ID)"
}

# ---------------------------------------------------------------------------
# Step 4: Discord Setup
# ---------------------------------------------------------------------------
validate_discord_token() {
    local token="$1"
    if ! $HAS_CURL; then
        warn "curl not available — skipping token validation"
        return 0
    fi
    local response
    response=$(curl -sf -H "Authorization: Bot $token" \
        "https://discord.com/api/v10/users/@me" 2>/dev/null)
    if [[ $? -eq 0 && -n "$response" ]]; then
        local botname
        botname=$(echo "$response" | "$VENV_DIR/bin/python3" -c "import json,sys; print(json.load(sys.stdin).get('username','?'))" 2>/dev/null || echo "?")
        success "Discord token valid — bot: $botname"
        return 0
    fi
    return 1
}

step_discord() {
    CURRENT_STEP=4
    step_header 4 "Discord Bridge"

    ask_yn "Configure Discord bot?" "y"
    if [[ "$REPLY" == "n" ]]; then
        info "Skipping Discord setup."
        return 0
    fi
    DISCORD_ENABLED=true

    # Check existing token in keyring
    local existing_token
    existing_token=$("$VENV_DIR/bin/python3" -c "
import sys; sys.path.insert(0, '$SCRIPT_DIR')
from src.credential_store import get_secret
t = get_secret('discord_token')
print('yes' if t else 'no')" 2>/dev/null || echo "no")

    if [[ "$existing_token" == "yes" ]]; then
        success "Discord token already stored in keyring"
        ask_yn "Replace existing token?" "n"
        if [[ "$REPLY" == "n" ]]; then
            info "Keeping existing token."
            # Ask for optional channel
            _ask_discord_channel
            return 0
        fi
    fi

    echo ""
    dim "  To get a Discord bot token:"
    dim "  1. Go to https://discord.com/developers/applications"
    dim "  2. Create application → Bot → Reset Token → Copy"
    dim "  3. Enable MESSAGE CONTENT intent under Bot → Privileged Intents"
    dim "  4. Invite with: OAuth2 → URL Generator → bot + applications.commands"
    echo ""

    local attempts=0
    while [[ $attempts -lt 3 ]]; do
        ask_secret "Discord bot token"
        DISCORD_TOKEN="$REPLY"

        if [[ -z "$DISCORD_TOKEN" ]]; then
            warn "Empty token — skipping Discord"
            DISCORD_ENABLED=false
            return 0
        fi

        if validate_discord_token "$DISCORD_TOKEN"; then
            # Store via Python stdin (not CLI argument)
            echo "$DISCORD_TOKEN" | "$VENV_DIR/bin/python3" -c "
import sys; sys.path.insert(0, '$SCRIPT_DIR')
from src.credential_store import set_secret
set_secret('discord_token', sys.stdin.readline().strip())"
            success "Token stored in keyring"
            break
        else
            error "Token validation failed"
            attempts=$((attempts + 1))
            if [[ $attempts -ge 3 ]]; then
                warn "3 failed attempts — skipping Discord token"
                DISCORD_ENABLED=false
                return 0
            fi
        fi
    done

    _ask_discord_channel
}

_ask_discord_channel() {
    echo ""
    ask "Default Discord channel ID (blank to skip)" ""
    DISCORD_CHANNEL_ID="$REPLY"
    if [[ -n "$DISCORD_CHANNEL_ID" ]]; then
        ask "Channel alias" "general"
        DISCORD_CHANNEL_ALIAS="$REPLY"
    fi
}

# ---------------------------------------------------------------------------
# Step 5: Telegram Setup
# ---------------------------------------------------------------------------
validate_telegram_token() {
    local token="$1"
    if ! $HAS_CURL; then
        warn "curl not available — skipping token validation"
        return 0
    fi
    local response
    response=$(curl -sf "https://api.telegram.org/bot${token}/getMe" 2>/dev/null)
    if [[ $? -eq 0 ]] && echo "$response" | "$VENV_DIR/bin/python3" -c "import json,sys; d=json.load(sys.stdin); exit(0 if d.get('ok') else 1)" 2>/dev/null; then
        local botname
        botname=$(echo "$response" | "$VENV_DIR/bin/python3" -c "import json,sys; print(json.load(sys.stdin)['result']['username'])" 2>/dev/null || echo "?")
        success "Telegram token valid — bot: @$botname"
        return 0
    fi
    return 1
}

step_telegram() {
    CURRENT_STEP=5
    step_header 5 "Telegram Bridge"

    ask_yn "Configure Telegram bot?" "n"
    if [[ "$REPLY" == "n" ]]; then
        info "Skipping Telegram setup."
        return 0
    fi
    TELEGRAM_ENABLED=true

    # Check existing token
    local existing_token
    existing_token=$("$VENV_DIR/bin/python3" -c "
import sys; sys.path.insert(0, '$SCRIPT_DIR')
from src.credential_store import get_secret
t = get_secret('telegram_token')
print('yes' if t else 'no')" 2>/dev/null || echo "no")

    if [[ "$existing_token" == "yes" ]]; then
        success "Telegram token already stored in keyring"
        ask_yn "Replace existing token?" "n"
        if [[ "$REPLY" == "n" ]]; then
            info "Keeping existing token."
            _ask_telegram_admins
            return 0
        fi
    fi

    echo ""
    dim "  To get a Telegram bot token:"
    dim "  1. Open Telegram, search for @BotFather"
    dim "  2. Send /newbot and follow the prompts"
    dim "  3. Copy the HTTP API token"
    echo ""

    local attempts=0
    while [[ $attempts -lt 3 ]]; do
        ask_secret "Telegram bot token"
        local tg_token="$REPLY"

        if [[ -z "$tg_token" ]]; then
            warn "Empty token — skipping Telegram"
            TELEGRAM_ENABLED=false
            return 0
        fi

        if validate_telegram_token "$tg_token"; then
            echo "$tg_token" | "$VENV_DIR/bin/python3" -c "
import sys; sys.path.insert(0, '$SCRIPT_DIR')
from src.credential_store import set_secret
set_secret('telegram_token', sys.stdin.readline().strip())"
            success "Token stored in keyring"
            TELEGRAM_TOKEN="$tg_token"
            break
        else
            error "Token validation failed"
            attempts=$((attempts + 1))
            if [[ $attempts -ge 3 ]]; then
                warn "3 failed attempts — skipping Telegram token"
                TELEGRAM_ENABLED=false
                return 0
            fi
        fi
    done

    _ask_telegram_admins
}

_ask_telegram_admins() {
    ask "Telegram admin user IDs (comma-separated, blank for none)" ""
    TELEGRAM_ADMIN_IDS="$REPLY"
}

# ---------------------------------------------------------------------------
# Step 6: WhatsApp Setup
# ---------------------------------------------------------------------------
step_whatsapp() {
    CURRENT_STEP=6
    step_header 6 "WhatsApp Bridge"

    if ! $NODE_AVAILABLE; then
        info "Node.js 22+ not available — skipping WhatsApp setup."
        return 0
    fi

    ask_yn "Configure WhatsApp bridge?" "n"
    if [[ "$REPLY" == "n" ]]; then
        info "Skipping WhatsApp setup."
        return 0
    fi
    WHATSAPP_ENABLED=true

    # npm install
    if [[ -d "$WA_BRIDGE_DIR/node_modules" ]]; then
        success "node_modules/ already exists"
        ask_yn "Re-run npm install?" "n"
        if [[ "$REPLY" == "y" ]]; then
            info "Running npm install..."
            (cd "$WA_BRIDGE_DIR" && npm install --no-fund --no-audit 2>&1) &>/dev/null &
            spinner $! "Installing npm packages"
            if (cd "$WA_BRIDGE_DIR" && npm install --no-fund --no-audit &>/dev/null); then
                success "npm packages installed"
            else
                warn "npm install had issues — bridge may still work"
            fi
        fi
    else
        info "Running npm install in bridge/whatsapp/..."
        (cd "$WA_BRIDGE_DIR" && npm install --no-fund --no-audit 2>&1) &>/dev/null &
        spinner $! "Installing npm packages"
        if (cd "$WA_BRIDGE_DIR" && npm install --no-fund --no-audit &>/dev/null); then
            success "npm packages installed"
        else
            error "npm install failed"
            step_failed "WhatsApp npm install"
            return 1
        fi
    fi

    # Owner phone
    local existing_phone=""
    if [[ -f "$CONFIG_FILE" ]]; then
        existing_phone=$("$VENV_DIR/bin/python3" -c "
import json
c = json.load(open('$CONFIG_FILE'))
print(c.get('whatsapp',{}).get('owner',''))" 2>/dev/null || echo "")
    fi

    ask "Owner phone number (international, no +)" "$existing_phone"
    WHATSAPP_OWNER_PHONE="$REPLY"

    echo ""
    dim "  WhatsApp QR pairing will happen when you start the bridge:"
    dim "    systemctl --user start echo-whatsapp-bridge"
    dim "    journalctl --user -u echo-whatsapp-bridge -f"
    dim "  Or open http://127.0.0.1:8098/qr in a browser."
    echo ""
    success "WhatsApp bridge prepared"
}

# ---------------------------------------------------------------------------
# Step 7: Configuration (merge into config.json)
# ---------------------------------------------------------------------------
step_config() {
    CURRENT_STEP=7
    step_header 7 "Configuration"

    # Backup existing config
    if [[ -f "$CONFIG_FILE" ]]; then
        local backup="$CONFIG_FILE.bak.$(date +%Y%m%d%H%M%S)"
        cp "$CONFIG_FILE" "$backup"
        success "Backup: $(basename "$backup")"
    fi

    # Build patch JSON and merge via Python
    "$VENV_DIR/bin/python3" << 'PYEOF' - \
        "$CONFIG_FILE" \
        "$BOT_NAME" \
        "$OWNER_DISCORD_ID" \
        "$ADMIN_IDS" \
        "$DISCORD_ENABLED" \
        "$DISCORD_CHANNEL_ID" \
        "$DISCORD_CHANNEL_ALIAS" \
        "$TELEGRAM_ENABLED" \
        "$TELEGRAM_ADMIN_IDS" \
        "$WHATSAPP_ENABLED" \
        "$WHATSAPP_OWNER_PHONE"
import json, sys, os
from pathlib import Path

args = sys.argv[1:]
config_path     = args[0]
bot_name        = args[1]
owner_discord   = args[2]
admin_ids_raw   = args[3]
discord_on      = args[4] == "true"
discord_ch_id   = args[5]
discord_ch_alias= args[6]
telegram_on     = args[7] == "true"
tg_admin_raw    = args[8]
whatsapp_on     = args[9] == "true"
wa_phone        = args[10]

# Load existing or create empty
if Path(config_path).exists():
    with open(config_path) as f:
        config = json.load(f)
else:
    config = {}

# --- bot section ---
bot = config.setdefault("bot", {})
if bot_name:
    bot["name"] = bot_name
bot.setdefault("default_model", "opus")
if owner_discord:
    bot["owner"] = owner_discord
if admin_ids_raw:
    bot["admins"] = [a.strip() for a in admin_ids_raw.split(",") if a.strip()]

# --- channels (preserve existing) ---
config.setdefault("channels", {})
if discord_on and discord_ch_id and discord_ch_alias:
    config["channels"][discord_ch_alias] = {
        "id": discord_ch_id,
        "default_model": "opus"
    }

# --- telegram_channels (preserve existing) ---
config.setdefault("telegram_channels", {})

# --- whatsapp ---
wa = config.setdefault("whatsapp", {})
wa["enabled"] = whatsapp_on
wa.setdefault("bridge_url", "http://127.0.0.1:8098")
if wa_phone:
    wa["owner"] = wa_phone
wa.setdefault("admins", [])
config.setdefault("whatsapp_channels", {})

# --- heartbeat ---
hb = config.setdefault("heartbeat", {})
hb.setdefault("enabled", True)
hb.setdefault("interval_minutes", 30)

# --- ollama ---
ol = config.setdefault("ollama", {})
ol.setdefault("url", "http://localhost:11434")

# --- paths ---
paths = config.setdefault("paths", {})
paths.setdefault("personality", "personality/")
paths.setdefault("tools", "tools/")
paths.setdefault("memory", "memory/")
paths.setdefault("logs", "logs/")
paths.setdefault("sessions", "sessions/")

# Write
with open(config_path, "w") as f:
    json.dump(config, f, indent=2, ensure_ascii=False)
    f.write("\n")

print("OK")
PYEOF

    if [[ $? -eq 0 ]]; then
        success "config.json written"
    else
        error "Failed to write config.json"
        step_failed "Config write"
    fi
}

# ---------------------------------------------------------------------------
# Step 8: Systemd Services
# ---------------------------------------------------------------------------
step_systemd() {
    CURRENT_STEP=8
    step_header 8 "Systemd Services"

    if ! $HAS_SYSTEMCTL; then
        info "systemctl not available — skipping service installation."
        return 0
    fi

    mkdir -p "$SYSTEMD_DIR"

    # --- echo-core.service ---
    local svc_core="$SYSTEMD_DIR/echo-core.service"
    local core_changed=false
    local core_content
    core_content=$(cat << EOF
[Unit]
Description=Echo Core Bot (Discord + Telegram + WhatsApp)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=$SCRIPT_DIR
ExecStart=$VENV_DIR/bin/python3 src/main.py
Restart=always
RestartSec=5
KillMode=mixed
TimeoutStopSec=10
Environment=HOME=$HOME
Environment="PATH=$HOME/.local/bin:$VENV_DIR/bin:/usr/local/bin:/usr/bin:/bin"

[Install]
WantedBy=default.target
EOF
)

    if [[ -f "$svc_core" ]]; then
        success "echo-core.service exists"
        ask_yn "Regenerate echo-core.service?" "n"
        [[ "$REPLY" == "y" ]] && core_changed=true
    else
        core_changed=true
    fi

    if $core_changed; then
        echo "$core_content" > "$svc_core"
        success "Wrote echo-core.service"
    fi

    # --- echo-whatsapp-bridge.service ---
    local wa_changed=false
    if $WHATSAPP_ENABLED; then
        local svc_wa="$SYSTEMD_DIR/echo-whatsapp-bridge.service"
        local wa_content
        wa_content=$(cat << EOF
[Unit]
Description=Echo Core WhatsApp Bridge (Baileys)
After=network-online.target
Wants=network-online.target
Before=echo-core.service

[Service]
Type=simple
WorkingDirectory=$WA_BRIDGE_DIR
ExecStart=/usr/bin/node index.js
Restart=always
RestartSec=5
KillMode=process
Environment=HOME=$HOME
Environment="PATH=/usr/local/bin:/usr/bin:/bin"

[Install]
WantedBy=default.target
EOF
)
        if [[ -f "$svc_wa" ]]; then
            success "echo-whatsapp-bridge.service exists"
            ask_yn "Regenerate echo-whatsapp-bridge.service?" "n"
            [[ "$REPLY" == "y" ]] && wa_changed=true
        else
            wa_changed=true
        fi

        if $wa_changed; then
            echo "$wa_content" > "$svc_wa"
            success "Wrote echo-whatsapp-bridge.service"
        fi
    fi

    # daemon-reload + enable
    if $core_changed || $wa_changed; then
        systemctl --user daemon-reload
        success "daemon-reload done"
    fi

    systemctl --user enable echo-core.service &>/dev/null
    success "echo-core.service enabled"

    if $WHATSAPP_ENABLED; then
        systemctl --user enable echo-whatsapp-bridge.service &>/dev/null
        success "echo-whatsapp-bridge.service enabled"
    fi

    SERVICES_INSTALLED=true

    # Install `eco` CLI command
    local cli_target="$HOME/.local/bin/eco"
    mkdir -p "$HOME/.local/bin"
    if [[ -L "$cli_target" || -f "$cli_target" ]]; then
        success "eco CLI already installed at ~/.local/bin/eco"
    else
        ln -s "$SCRIPT_DIR/cli.py" "$cli_target"
        success "Installed eco CLI → ~/.local/bin/eco"
    fi

    # Start now?
    echo ""
    ask_yn "Start services now?" "n"
    if [[ "$REPLY" == "y" ]]; then
        START_NOW=true
        if $WHATSAPP_ENABLED; then
            systemctl --user start echo-whatsapp-bridge.service
            info "Starting WhatsApp bridge..."
            sleep 2
        fi
        systemctl --user start echo-core.service
        info "Starting Echo Core..."
        sleep 2

        local status
        status=$(systemctl --user is-active echo-core.service 2>/dev/null)
        if [[ "$status" == "active" ]]; then
            success "echo-core.service is running"
        else
            warn "echo-core.service status: $status"
        fi

        if $WHATSAPP_ENABLED; then
            status=$(systemctl --user is-active echo-whatsapp-bridge.service 2>/dev/null)
            if [[ "$status" == "active" ]]; then
                success "echo-whatsapp-bridge.service is running"
            else
                warn "echo-whatsapp-bridge.service status: $status"
            fi
        fi
    fi
}

# ---------------------------------------------------------------------------
# Step 9: Health Check
# ---------------------------------------------------------------------------
step_healthcheck() {
    CURRENT_STEP=9
    step_header 9 "Health Check"

    local issues=0

    # Config valid JSON
    if [[ -f "$CONFIG_FILE" ]] && "$VENV_DIR/bin/python3" -c "import json; json.load(open('$CONFIG_FILE'))" 2>/dev/null; then
        success "config.json is valid JSON"
    else
        error "config.json is missing or invalid"
        issues=$((issues + 1))
    fi

    # Secrets in keyring
    local secrets_report
    secrets_report=$("$VENV_DIR/bin/python3" -c "
import sys; sys.path.insert(0, '$SCRIPT_DIR')
from src.credential_store import get_secret
dt = 'yes' if get_secret('discord_token') else 'no'
tt = 'yes' if get_secret('telegram_token') else 'no'
print(f'{dt},{tt}')" 2>/dev/null || echo "no,no")
    local dt tt
    dt=$(echo "$secrets_report" | cut -d, -f1)
    tt=$(echo "$secrets_report" | cut -d, -f2)

    if $DISCORD_ENABLED; then
        if [[ "$dt" == "yes" ]]; then
            success "Discord token in keyring"
        else
            error "Discord token NOT in keyring"
            issues=$((issues + 1))
        fi
    fi

    if $TELEGRAM_ENABLED; then
        if [[ "$tt" == "yes" ]]; then
            success "Telegram token in keyring"
        else
            error "Telegram token NOT in keyring"
            issues=$((issues + 1))
        fi
    fi

    # Directories writable
    for d in logs sessions memory; do
        local full="$SCRIPT_DIR/$d"
        if [[ -d "$full" && -w "$full" ]]; then
            success "$d/ writable"
        elif [[ ! -d "$full" ]]; then
            mkdir -p "$full" 2>/dev/null
            if [[ -d "$full" ]]; then
                success "$d/ created"
            else
                error "Cannot create $d/"
                issues=$((issues + 1))
            fi
        else
            error "$d/ not writable"
            issues=$((issues + 1))
        fi
    done

    # Claude CLI
    if $HAS_CLAUDE; then
        success "Claude CLI available"
    else
        error "Claude CLI not found"
        issues=$((issues + 1))
    fi

    # Service status (if installed)
    if $SERVICES_INSTALLED && $HAS_SYSTEMCTL; then
        local core_status
        core_status=$(systemctl --user is-active echo-core.service 2>/dev/null || echo "not-found")
        if [[ "$core_status" == "active" ]]; then
            success "echo-core.service: active"
        elif [[ "$core_status" == "inactive" ]]; then
            info "echo-core.service: inactive (not started)"
        else
            warn "echo-core.service: $core_status"
        fi
    fi

    echo ""
    if [[ $issues -eq 0 ]]; then
        success "All health checks passed"
    else
        warn "$issues issue(s) found"
    fi
}

# ---------------------------------------------------------------------------
# Step 10: Summary
# ---------------------------------------------------------------------------
step_summary() {
    CURRENT_STEP=10
    step_header 10 "Summary"

    local check="${C_GREEN}✓${C_RESET}"
    local cross="${C_RED}✗${C_RESET}"

    echo ""
    echo -e "${C_ORANGE}┌────────────────────────────────────────┐${C_RESET}"
    echo -e "${C_ORANGE}│${C_RESET}  ${C_BOLD}Echo Core Setup Complete${C_RESET}              ${C_ORANGE}│${C_RESET}"
    echo -e "${C_ORANGE}├────────────────────────────────────────┤${C_RESET}"
    printf "${C_ORANGE}│${C_RESET}  Bot name:    %-23s ${C_ORANGE}│${C_RESET}\n" "$BOT_NAME"
    printf "${C_ORANGE}│${C_RESET}  Owner:       %-23s ${C_ORANGE}│${C_RESET}\n" "$OWNER_DISCORD_ID"
    echo -e "${C_ORANGE}├────────────────────────────────────────┤${C_RESET}"
    echo -e "${C_ORANGE}│${C_RESET}  Bridges:                              ${C_ORANGE}│${C_RESET}"
    if $DISCORD_ENABLED; then
        echo -e "${C_ORANGE}│${C_RESET}    $check Discord                        ${C_ORANGE}│${C_RESET}"
    else
        echo -e "${C_ORANGE}│${C_RESET}    $cross Discord (skipped)              ${C_ORANGE}│${C_RESET}"
    fi
    if $TELEGRAM_ENABLED; then
        echo -e "${C_ORANGE}│${C_RESET}    $check Telegram                       ${C_ORANGE}│${C_RESET}"
    else
        echo -e "${C_ORANGE}│${C_RESET}    $cross Telegram (skipped)             ${C_ORANGE}│${C_RESET}"
    fi
    if $WHATSAPP_ENABLED; then
        echo -e "${C_ORANGE}│${C_RESET}    $check WhatsApp                       ${C_ORANGE}│${C_RESET}"
    else
        echo -e "${C_ORANGE}│${C_RESET}    $cross WhatsApp (skipped)             ${C_ORANGE}│${C_RESET}"
    fi
    echo -e "${C_ORANGE}├────────────────────────────────────────┤${C_RESET}"
    if $SERVICES_INSTALLED; then
        echo -e "${C_ORANGE}│${C_RESET}    $check Systemd services installed     ${C_ORANGE}│${C_RESET}"
    else
        echo -e "${C_ORANGE}│${C_RESET}    $cross Systemd services (skipped)     ${C_ORANGE}│${C_RESET}"
    fi
    echo -e "${C_ORANGE}└────────────────────────────────────────┘${C_RESET}"

    # Write .setup-meta.json
    "$VENV_DIR/bin/python3" << METAEOF
import json
from datetime import datetime
meta = {
    "date": datetime.now().isoformat(),
    "bot_name": "$BOT_NAME",
    "discord": $($DISCORD_ENABLED && echo "True" || echo "False"),
    "telegram": $($TELEGRAM_ENABLED && echo "True" || echo "False"),
    "whatsapp": $($WHATSAPP_ENABLED && echo "True" || echo "False"),
    "services_installed": $($SERVICES_INSTALLED && echo "True" || echo "False")
}
with open("$META_FILE", "w") as f:
    json.dump(meta, f, indent=2)
    f.write("\n")
METAEOF
    success "Wrote .setup-meta.json"

    # Next steps
    echo ""
    echo -e "  ${C_BOLD}Next steps:${C_RESET}"
    echo ""
    if ! $START_NOW && $SERVICES_INSTALLED; then
        dim "  Start the bot:"
        echo -e "    ${C_CYAN}systemctl --user start echo-core${C_RESET}"
        echo ""
    fi
    if $WHATSAPP_ENABLED && ! $START_NOW; then
        dim "  Start WhatsApp bridge + pair via QR:"
        echo -e "    ${C_CYAN}systemctl --user start echo-whatsapp-bridge${C_RESET}"
        echo -e "    ${C_CYAN}curl http://127.0.0.1:8098/status${C_RESET}"
        echo ""
    fi
    dim "  View logs:"
    echo -e "    ${C_CYAN}journalctl --user -u echo-core -f${C_RESET}"
    echo ""
    dim "  Check status:"
    echo -e "    ${C_CYAN}./cli.py status${C_RESET}"
    echo -e "    ${C_CYAN}./cli.py doctor${C_RESET}"
    echo ""
    dim "  Manage secrets:"
    echo -e "    ${C_CYAN}./cli.py secrets list${C_RESET}"
    echo ""
    echo -e "  ${C_GREEN}${C_BOLD}Setup complete! 🎉${C_RESET}"
    echo ""
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
main() {
    step_welcome
    step_prerequisites
    step_venv
    step_identity
    step_discord
    step_telegram
    step_whatsapp
    step_config
    step_systemd
    step_healthcheck
    step_summary
}

main "$@"
