#!/bin/sh
# Clawdie Shell — Environment Configuration Module
# Purpose: Generate .env file with secrets and configuration
# POSIX-compliant (no bash-isms)

set -eu

# Configuration (can be overridden for testing)
CLAWDIE_HOME="${CLAWDIE_HOME:-/home/clawdie}"
ENV_FILE="${ENV_FILE:-$CLAWDIE_HOME/.env}"
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"

# Subnet base (default 10.0.0)
AGENT_SUBNET_BASE="${AGENT_SUBNET_BASE:-10.0.0}"

# ============================================================================
# MAIN ENTRY POINT
# ============================================================================

clawdie_shell_env_generate() {
  # Main orchestrator: generate .env file with all required variables.
  # In upgrade mode, secrets are NEVER regenerated — only new keys are appended.
  # This is the fix for the PC-BSD class of upgrade bug where new install
  # passwords orphan the existing database.

  log_msg "[env] Starting .env generation (mode: ${CLAWDIE_BOOT_MODE:-install})"

  # ── Upgrade path: preserve secrets, append only missing keys ──────────────
  if [ "${CLAWDIE_BOOT_MODE:-install}" = "upgrade" ] && [ -f "$ENV_FILE" ]; then
    clawdie_shell_env_append_new_keys || {
      log_msg "[env] ERROR: Failed to append new .env keys"
      return 1
    }
    clawdie_shell_env_validate || log_msg "[env] WARNING: .env validation found issues (upgrade)"
    echo "[ENV] SUCCESS" >> "$PROGRESS_FILE"
    log_msg "[env] Upgrade .env complete — existing secrets preserved"
    return 0
  fi

  # ── Fresh install path ─────────────────────────────────────────────────────

  # Validate required inputs
  if [ -z "${ASSISTANT_NAME:-}" ]; then
    log_msg "[env] ERROR: ASSISTANT_NAME not set"
    return 1
  fi

  if [ -z "${AGENT_DOMAIN:-}" ]; then
    log_msg "[env] ERROR: AGENT_DOMAIN not set"
    return 1
  fi

  if [ -z "${TZ:-}" ]; then
    TZ="UTC"
    log_msg "[env] WARNING: TZ not set, defaulting to UTC"
  fi
  if [ -z "${SYSTEM_LOCALE:-}" ]; then
    SYSTEM_LOCALE="en_US.UTF-8"
    log_msg "[env] WARNING: SYSTEM_LOCALE not set, defaulting to ${SYSTEM_LOCALE}"
  fi
  DISPLAY_LOCALE="${DISPLAY_LOCALE:-$SYSTEM_LOCALE}"
  ASSISTANT_LOCALE="${ASSISTANT_LOCALE:-$SYSTEM_LOCALE}"
  KEYMAP="${KEYMAP:-us}"

  # Step 1: Create directory
  mkdir -p "$CLAWDIE_HOME"
  chown clawdie:clawdie "$CLAWDIE_HOME" 2>/dev/null || true

  # Step 2: Generate all .env variables
  clawdie_shell_env_write_file || {
    log_msg "[env] ERROR: Failed to write .env file"
    return 1
  }

  log_msg "[env] .env file generated successfully"

  # Step 3: Validate
  clawdie_shell_env_validate || {
    log_msg "[env] ERROR: .env validation failed"
    return 1
  }

  echo "[ENV] SUCCESS" >> "$PROGRESS_FILE"
  log_msg "[env] Environment configuration complete"
}

clawdie_shell_env_append_new_keys() {
  # Upgrade-only: read the existing .env and add any keys introduced in the new
  # version that are not yet present. Never touches existing values.
  # Pattern: if key is absent → append with safe default; if present → skip.

  log_msg "[env] Upgrade mode: appending missing keys to existing .env"

  _env_append_if_missing() {
    _key="$1"; _val="$2"
    if ! grep -q "^${_key}=" "$ENV_FILE" 2>/dev/null; then
      printf '%s=%s\n' "$_key" "$_val" >> "$ENV_FILE"
      log_msg "[env] Appended new key: $_key"
    fi
  }

  # Keys added in v0.10.x / v1.0.0 that older installs may not have.
  # Do not append provider/model defaults here; Clawdie-AI resolves those at
  # runtime unless the operator explicitly configures them.
  _env_append_if_missing "DB_RUNTIME"         '"jail"'
  _env_append_if_missing "EMBED_DIMENSIONS"   '"1024"'
  _env_append_if_missing "LOCAL_LLM_PROVIDER" '"none"'
  _env_append_if_missing "FEATURE_OLLAMA"     '"NO"'
  _env_append_if_missing "FEATURE_LLAMA_CPP"  '"NO"'
  _env_append_if_missing "CLAWDIE_PROFILE"    '"core"'

  _env_append_if_missing "CONTROLPLANE_SHARED_SECRET"  '""'
  _env_append_if_missing "CONTROLPLANE_BIND_HOST"      '"127.0.0.1"'
  _env_append_if_missing "CONTROLPLANE_HOST_IP"        "\"${AGENT_SUBNET_BASE}.1\""
  _env_append_if_missing "CONTROLPLANE_EXPOSURE"       '"internal"'
  _env_append_if_missing "CONTROLPLANE_AUTH_MODE"      '"local_trusted"'
  _env_append_if_missing "CONTROLPLANE_PORT"           '"3100"'
  _env_append_if_missing "BETTER_AUTH_URL"             '"http://127.0.0.1:3100"'
  _env_append_if_missing "BETTER_AUTH_SECRET"           '""'
  _env_append_if_missing "GIT_LOCAL_URL"               "\"git@${AGENT_SUBNET_BASE}.6:/srv/git/${ASSISTANT_NAME:-clawdie}-ai.git\""

  chmod 600 "$ENV_FILE" 2>/dev/null || true
  chown clawdie:clawdie "$ENV_FILE" 2>/dev/null || true

  log_msg "[env] Append complete ($(wc -l < "$ENV_FILE") lines total)"
}

# ============================================================================
# .ENV FILE GENERATION
# ============================================================================

clawdie_shell_env_write_file() {
  # Write a minimal .env seed file.
  #
  # This file is copied into the Clawdie-AI repo by the deploy module and then
  # completed by Clawdie-AI onboarding (secrets, derived defaults, URLs, etc).

  # Derive agent name from assistant name (lowercase, strip non-alnum)
  local agent_name
  agent_name=$(echo "$ASSISTANT_NAME" | tr 'A-Z' 'a-z' | sed 's/[^a-z0-9]//g')

  # Generate controlplane auth secrets (one-time at install)
  local cp_secret auth_secret
  cp_secret=$(openssl rand -base64 32)
  auth_secret=$(openssl rand -base64 32)

  # Provider/model are intentionally unset by default; Clawdie-AI resolves the
  # recommended runtime profile and post-install setup writes the operator's
  # chosen provider. Embedding base URL is left empty when no OpenRouter key
  # exists so config.ts can dynamically pick OpenRouter or local at runtime.
  local pi_tui_provider pi_tui_model embed_base_url embed_model embed_api_key
  pi_tui_provider="${PI_TUI_PROVIDER:-}"
  pi_tui_model="${PI_TUI_MODEL:-}"
  if [ -n "${EMBED_BASE_URL:-}" ]; then
    embed_base_url="$EMBED_BASE_URL"
  elif [ -n "${OPENROUTER_API_KEY:-}" ]; then
    embed_base_url="https://openrouter.ai/api/v1"
  else
    embed_base_url=""
  fi
  embed_model="${EMBED_MODEL:-BAAI/bge-m3}"
  if [ -n "${EMBED_API_KEY:-}" ]; then
    embed_api_key="$EMBED_API_KEY"
  elif [ "$embed_base_url" = "https://openrouter.ai/api/v1" ]; then
    embed_api_key="${OPENROUTER_API_KEY:-}"
  else
    embed_api_key=""
  fi

  # Remove existing .env if present
  rm -f "$ENV_FILE" 2>/dev/null || true

  # Create new .env with restricted permissions
  touch "$ENV_FILE"
  chmod 600 "$ENV_FILE"
  chown clawdie:clawdie "$ENV_FILE" 2>/dev/null || true

  # Write .env file
  cat > "$ENV_FILE" <<EOF
# Clawdie-AI environment configuration (seed)
# Auto-generated by clawdie-iso firstboot installer.
# Secrets and derived defaults are generated by Clawdie-AI onboarding.

# === Identity ===
ASSISTANT_NAME="$ASSISTANT_NAME"
AGENT_NAME="$agent_name"
AGENT_GENDER="${AGENT_GENDER:-f}"
CLAWDIE_PROFILE="${CLAWDIE_PROFILE:-core}"
AGENT_DOMAIN="$AGENT_DOMAIN"
AGENT_INTERNAL_DOMAIN="${agent_name}.home.arpa"
TZ="$TZ"
DISPLAY_LOCALE="$DISPLAY_LOCALE"
ASSISTANT_LOCALE="$ASSISTANT_LOCALE"
SYSTEM_LOCALE="$SYSTEM_LOCALE"
KEYMAP="$KEYMAP"

# === LLM Provider ===
PI_TUI_PROVIDER="$pi_tui_provider"
PI_TUI_MODEL="$pi_tui_model"
ZAI_API_KEY="${ZAI_API_KEY:-}"
ZAI_API_BASE="${ZAI_API_BASE:-https://api.z.ai/api/coding/paas/v4}"
OPENROUTER_API_KEY="${OPENROUTER_API_KEY:-}"
ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}"
CLAUDE_CODE_OAUTH_TOKEN="${CLAUDE_CODE_OAUTH_TOKEN:-}"

# === Embeddings ===
EMBED_BASE_URL="$embed_base_url"
EMBED_MODEL="$embed_model"
EMBED_API_KEY="$embed_api_key"
EMBED_DIMENSIONS="${EMBED_DIMENSIONS:-1024}"

# === Database ===
# DB_RUNTIME=jail  — PostgreSQL runs inside a bastille jail (default, provisioned by installer)
# DB_RUNTIME=host  — PostgreSQL runs on the host; set DB_HOST to warden0 gateway IP
DB_RUNTIME="jail"

# === Network Configuration (warden0) ===
AGENT_SUBNET_BASE="$AGENT_SUBNET_BASE"
WARDEN_SUBNET_BASE="$AGENT_SUBNET_BASE"
WARDEN_SUBNET="${AGENT_SUBNET_BASE}.0/24"
WARDEN_GATEWAY="${AGENT_SUBNET_BASE}.1"

# === Features (optional) ===
FEATURE_TELEGRAM="${FEATURE_TELEGRAM:-NO}"
FEATURE_GIT="${FEATURE_GIT:-YES}"
FEATURE_GITEA="${FEATURE_GITEA:-NO}"
CODE_HOSTING_MODE="${CODE_HOSTING_MODE:-git}"
FEATURE_TAILSCALE="${FEATURE_TAILSCALE:-NO}"
TAILSCALE_AUTHKEY="${TAILSCALE_AUTHKEY:-}"
LOCAL_LLM_PROVIDER="${LOCAL_LLM_PROVIDER:-none}"
FEATURE_OLLAMA="${FEATURE_OLLAMA:-NO}"
FEATURE_LLAMA_CPP="${FEATURE_LLAMA_CPP:-NO}"
FEATURE_OLLAMA_HPP="${FEATURE_OLLAMA_HPP:-NO}"

# === Telegram ===
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_ADMIN_IDS="${TELEGRAM_ADMIN_IDS:-${TELEGRAM_ADMIN_ID:-}}"

# === Optional: SSH Public Key (if provided at install) ===
SSH_PUBLIC_KEY="${SSH_PUBLIC_KEY:-}"

# === Controlplane (multi-agent orchestration) ===
CONTROLPLANE_SHARED_SECRET="$cp_secret"
CONTROLPLANE_BIND_HOST="127.0.0.1"
CONTROLPLANE_HOST_IP="${AGENT_SUBNET_BASE}.1"
CONTROLPLANE_EXPOSURE="internal"
CONTROLPLANE_AUTH_MODE="local_trusted"
CONTROLPLANE_PORT="3100"
BETTER_AUTH_URL="http://127.0.0.1:3100"
BETTER_AUTH_SECRET="$auth_secret"

# === Git (local bare repo on git jail) ===
GIT_LOCAL_URL="git@${AGENT_SUBNET_BASE}.6:/srv/git/${ASSISTANT_NAME}-ai.git"
EOF

  log_msg "[env] Wrote .env with $(wc -l < "$ENV_FILE") configuration lines"
  return 0
}

# ============================================================================
# VALIDATION
# ============================================================================

clawdie_shell_env_validate() {
  # Verify .env file is properly formatted

  if [ ! -f "$ENV_FILE" ]; then
    log_msg "[env] ERROR: .env file not found: $ENV_FILE"
    return 1
  fi

  # Check permissions (should be 600)
  local perms
  perms=$(stat -f "%OLp" "$ENV_FILE" 2>/dev/null || stat -c "%a" "$ENV_FILE" 2>/dev/null || echo "")
  if [ "$perms" != "600" ] && [ -n "$perms" ]; then
    log_msg "[env] WARNING: .env permissions are $perms (should be 600)"
  fi

  # Check for required variables
  local required_vars="ASSISTANT_NAME AGENT_NAME AGENT_DOMAIN AGENT_INTERNAL_DOMAIN TZ SYSTEM_LOCALE DISPLAY_LOCALE ASSISTANT_LOCALE KEYMAP"
  local missing=0
  for var in $required_vars; do
    if ! grep -q "^$var=" "$ENV_FILE" 2>/dev/null; then
      log_msg "[env] ERROR: Missing required variable: $var"
      missing=$((missing + 1))
    fi
  done

  if [ $missing -gt 0 ]; then
    return 1
  fi

  log_msg "[env] .env validation passed ($(wc -l < "$ENV_FILE") lines)"
  return 0
}

# ============================================================================
# LOGGING HELPER
# ============================================================================

log_msg() {
  echo "$(date '+%H:%M:%S') $1" | tee -a "$LOG_FILE" 2>/dev/null || true
}

# Only run if sourced directly (not during test)
if [ "${SHELL_ENV_TEST:-0}" -eq 0 ]; then
  clawdie_shell_env_generate
fi
