#!/usr/bin/env bash
set -euo pipefail

PROGRAM_NAME="trustapi-setup"
VERSION="0.2.0"

DEFAULT_PROVIDER="vibediary"
DEFAULT_LANGUAGE="en"
DEFAULT_TRUSTAPI_ANTHROPIC_BASE_URL="https://trustapi.app/api"
DEFAULT_TRUSTAPI_OPENAI_BASE_URL="https://trustapi.app/api/v1"
DEFAULT_TRUSTAPI_API_KEY_ENV="TRUSTAPI_API_KEY"
DEFAULT_TRUSTAPI_CODEX_PROFILE="trustapi"
DEFAULT_VIBEDIARY_ANTHROPIC_BASE_URL="https://vibediary.app/api"
DEFAULT_VIBEDIARY_OPENAI_BASE_URL="https://vibediary.app/api/v1"
DEFAULT_VIBEDIARY_API_KEY_ENV="VIBEDIARY_API_KEY"
DEFAULT_VIBEDIARY_CODEX_PROFILE="vibediary"
DEFAULT_CUSTOM_API_KEY_ENV="CUSTOM_API_KEY"
DEFAULT_CUSTOM_CODEX_PROFILE="custom"
DEFAULT_CODEX_MODEL="gpt-5.4"

SHELL_MARKER_BEGIN="# >>> trustapi-setup >>>"
SHELL_MARKER_END="# <<< trustapi-setup <<<"
CODEX_MARKER_BEGIN="# >>> trustapi-setup codex >>>"
CODEX_MARKER_END="# <<< trustapi-setup codex <<<"

PROVIDER="$DEFAULT_PROVIDER"
PROVIDER_EXPLICIT=false
LANGUAGE=""
LANGUAGE_EXPLICIT=false
ANTHROPIC_BASE_URL=""
ANTHROPIC_BASE_URL_EXPLICIT=false
OPENAI_BASE_URL=""
OPENAI_BASE_URL_EXPLICIT=false
API_KEY="${VIBEDIARY_API_KEY:-${TRUSTAPI_API_KEY:-${OPENAI_API_KEY:-${ANTHROPIC_API_KEY:-}}}}"
API_KEY_ENV=""
API_KEY_ENV_EXPLICIT=false
CODEX_PROFILE=""
CODEX_PROFILE_EXPLICIT=false
CODEX_PROVIDER_ID=""
CODEX_MODEL=""
SHELL_PROFILE=""
PRINT_ONLY=false
UNINSTALL=false

SKIP_CLAUDE=false
SKIP_CLAUDE_VSCODE=false
SKIP_CODEX=false
SKIP_CODEX_VSCODE=false
SKIP_OPENCLAW=false
SKIP_CURSOR=false

INTERACTIVE_MODE=false
PROVIDER_DISPLAY=""

OS_NAME=""
ARCH_NAME=""
ENV_DIR=""
ENV_FILE=""
BACKUP_DIR=""
CODEX_CONFIG=""
CLAUDE_SETTINGS=""
SELECTED_SHELL_PROFILE=""

DETECT_CLAUDE=false
DETECT_CLAUDE_VSCODE=false
DETECT_CODEX=false
DETECT_CODEX_VSCODE=false
DETECT_OPENCLAW=false
DETECT_CURSOR=false

SELECT_CLAUDE=false
SELECT_CLAUDE_VSCODE=false
SELECT_CODEX=false
SELECT_CODEX_VSCODE=false
SELECT_OPENCLAW=false
SELECT_CURSOR=false

CLAUDE_VERSION=""
CODEX_VERSION=""
OPENCLAW_VERSION=""
CURSOR_VERSION=""

usage() {
  cat <<'EOF'
Usage: setup.sh [OPTIONS]

Post-install setup for Claude Code, Codex, OpenClaw, and Cursor on Linux/macOS.

Options:
  --provider NAME           provider id: vibediary (default) | trustapi | custom
  --anthropic-base-url URL  Anthropic-compatible base URL
  --openai-base-url URL     OpenAI Responses-compatible base URL
  --api-key KEY             API key; when omitted starts the interactive wizard
  --api-key-env NAME        Environment variable name for the shared API key
  --codex-profile NAME      Codex profile name
  --shell-profile PATH      Shell profile to patch explicitly
  --lang LANG               UI language: en | zh
  --skip-claude             Skip Claude Code CLI
  --skip-claude-vscode      Skip Claude Code VS Code config
  --skip-codex              Skip Codex CLI
  --skip-codex-vscode       Skip Codex VS Code config
  --skip-openclaw           Skip OpenClaw config
  --skip-cursor             Skip Cursor env setup
  --print-only              Print generated config without writing files
  --uninstall               Remove managed config
  -h, --help                Show help
EOF
}

info() {
  printf '[INFO] %s\n' "$*"
}

warn() {
  printf '[WARN] %s\n' "$*" >&2
}

die() {
  printf '[ERROR] %s\n' "$*" >&2
  exit 1
}

text() {
  local en="$1"
  local zh="$2"
  if [[ "$LANGUAGE" == "zh" ]]; then
    printf '%s' "$zh"
  else
    printf '%s' "$en"
  fi
}

print_step() {
  local step="$1"
  local title_en="$2"
  local title_zh="$3"
  printf '\n[%s] %s\n' "$step" "$(text "$title_en" "$title_zh")"
}

trim() {
  local value="$1"
  value="${value#"${value%%[![:space:]]*}"}"
  value="${value%"${value##*[![:space:]]}"}"
  printf '%s' "$value"
}

shell_quote() {
  local value="$1"
  value=${value//\'/\'\\\'\'}
  printf "'%s'" "$value"
}

toml_quote() {
  local value="$1"
  value=${value//\\/\\\\}
  value=${value//\"/\\\"}
  printf '"%s"' "$value"
}

ensure_arg() {
  local flag="$1"
  local value="${2:-}"
  [[ -n "$value" ]] || die "missing value for $flag"
}

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --provider)
        ensure_arg "$1" "${2:-}"
        PROVIDER="$2"
        PROVIDER_EXPLICIT=true
        shift 2
        ;;
      --anthropic-base-url)
        ensure_arg "$1" "${2:-}"
        ANTHROPIC_BASE_URL="$2"
        ANTHROPIC_BASE_URL_EXPLICIT=true
        shift 2
        ;;
      --openai-base-url)
        ensure_arg "$1" "${2:-}"
        OPENAI_BASE_URL="$2"
        OPENAI_BASE_URL_EXPLICIT=true
        shift 2
        ;;
      --api-key)
        ensure_arg "$1" "${2:-}"
        API_KEY="$2"
        shift 2
        ;;
      --api-key-env)
        ensure_arg "$1" "${2:-}"
        API_KEY_ENV="$2"
        API_KEY_ENV_EXPLICIT=true
        shift 2
        ;;
      --codex-profile)
        ensure_arg "$1" "${2:-}"
        CODEX_PROFILE="$2"
        CODEX_PROFILE_EXPLICIT=true
        shift 2
        ;;
      --shell-profile)
        ensure_arg "$1" "${2:-}"
        SHELL_PROFILE="$2"
        shift 2
        ;;
      --lang)
        ensure_arg "$1" "${2:-}"
        LANGUAGE="$2"
        LANGUAGE_EXPLICIT=true
        shift 2
        ;;
      --skip-claude)
        SKIP_CLAUDE=true
        shift
        ;;
      --skip-claude-vscode)
        SKIP_CLAUDE_VSCODE=true
        shift
        ;;
      --skip-codex)
        SKIP_CODEX=true
        shift
        ;;
      --skip-codex-vscode)
        SKIP_CODEX_VSCODE=true
        shift
        ;;
      --skip-openclaw)
        SKIP_OPENCLAW=true
        shift
        ;;
      --skip-cursor)
        SKIP_CURSOR=true
        shift
        ;;
      --print-only)
        PRINT_ONLY=true
        shift
        ;;
      --uninstall)
        UNINSTALL=true
        shift
        ;;
      -h|--help)
        usage
        exit 0
        ;;
      *)
        die "unknown option: $1"
        ;;
    esac
  done
}

validate_lang() {
  case "$LANGUAGE" in
    ""|en|zh) ;;
    *)
      die "invalid --lang: $LANGUAGE"
      ;;
  esac
}

detect_platform() {
  OS_NAME="$(uname -s)"
  ARCH_NAME="$(uname -m)"
  case "$OS_NAME" in
    Linux|Darwin) ;;
    *)
      die "unsupported platform: $OS_NAME (Linux and macOS only)"
      ;;
  esac
}

resolve_paths() {
  local config_root
  config_root="${XDG_CONFIG_HOME:-$HOME/.config}"
  ENV_DIR="$config_root/trustapi-setup"
  ENV_FILE="$ENV_DIR/env.sh"
  BACKUP_DIR="$ENV_DIR/backups"
  CODEX_CONFIG="$HOME/.codex/config.toml"
  CLAUDE_SETTINGS="$HOME/.claude/settings.json"
}

pick_shell_profile() {
  if [[ -n "$SHELL_PROFILE" ]]; then
    SELECTED_SHELL_PROFILE="$SHELL_PROFILE"
    return
  fi

  case "$(basename "${SHELL:-}")" in
    zsh)
      SELECTED_SHELL_PROFILE="$HOME/.zshrc"
      ;;
    bash)
      if [[ "$OS_NAME" == "Darwin" ]]; then
        SELECTED_SHELL_PROFILE="$HOME/.bash_profile"
      else
        SELECTED_SHELL_PROFILE="$HOME/.bashrc"
      fi
      ;;
    *)
      if [[ "$OS_NAME" == "Darwin" ]]; then
        SELECTED_SHELL_PROFILE="$HOME/.zshrc"
      else
        SELECTED_SHELL_PROFILE="$HOME/.bashrc"
      fi
      ;;
  esac
}

have_command() {
  command -v "$1" >/dev/null 2>&1
}

command_version() {
  local cmd="$1"
  "$cmd" --version 2>/dev/null | head -n 1 | tr -d '\r'
}

detect_tools() {
  if have_command claude; then
    DETECT_CLAUDE=true
    CLAUDE_VERSION="$(command_version claude)"
  fi
  if [[ -d "$HOME/.claude" ]]; then
    DETECT_CLAUDE_VSCODE=true
  fi
  if have_command codex; then
    DETECT_CODEX=true
    CODEX_VERSION="$(command_version codex)"
  fi
  if [[ -d "$HOME/.codex" ]]; then
    DETECT_CODEX_VSCODE=true
  fi
  if have_command openclaw; then
    DETECT_OPENCLAW=true
    OPENCLAW_VERSION="$(command_version openclaw)"
  fi
  if have_command cursor; then
    DETECT_CURSOR=true
    CURSOR_VERSION="$(command_version cursor)"
  fi
}

apply_default_tool_selection() {
  if [[ "$SKIP_CLAUDE" == true ]]; then
    SELECT_CLAUDE=false
  else
    SELECT_CLAUDE="$DETECT_CLAUDE"
  fi

  if [[ "$SKIP_CLAUDE_VSCODE" == true ]]; then
    SELECT_CLAUDE_VSCODE=false
  else
    SELECT_CLAUDE_VSCODE="$DETECT_CLAUDE_VSCODE"
  fi

  if [[ "$SKIP_CODEX" == true ]]; then
    SELECT_CODEX=false
  else
    SELECT_CODEX="$DETECT_CODEX"
  fi

  if [[ "$SKIP_CODEX_VSCODE" == true ]]; then
    SELECT_CODEX_VSCODE=false
  else
    SELECT_CODEX_VSCODE="$DETECT_CODEX_VSCODE"
  fi

  if [[ "$SKIP_OPENCLAW" == true ]]; then
    SELECT_OPENCLAW=false
  else
    SELECT_OPENCLAW="$DETECT_OPENCLAW"
  fi

  if [[ "$SKIP_CURSOR" == true ]]; then
    SELECT_CURSOR=false
  else
    SELECT_CURSOR="$DETECT_CURSOR"
  fi
}

any_selected() {
  [[ "$SELECT_CLAUDE" == true || "$SELECT_CLAUDE_VSCODE" == true || "$SELECT_CODEX" == true || "$SELECT_CODEX_VSCODE" == true || "$SELECT_OPENCLAW" == true || "$SELECT_CURSOR" == true ]]
}

uses_anthropic_base_url() {
  [[ "$SELECT_CLAUDE" == true || "$SELECT_CLAUDE_VSCODE" == true || "$SELECT_OPENCLAW" == true || "$SELECT_CURSOR" == true ]]
}

uses_openai_base_url() {
  [[ "$SELECT_CODEX" == true || "$SELECT_CODEX_VSCODE" == true ]]
}

uses_shell_env() {
  any_selected
}

validate_env_name() {
  [[ "$API_KEY_ENV" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || die "invalid --api-key-env: $API_KEY_ENV"
}

validate_codex_profile() {
  [[ "$CODEX_PROFILE" =~ ^[A-Za-z0-9._-]+$ ]] || die "invalid --codex-profile: $CODEX_PROFILE"
}

validate_url() {
  local name="$1"
  local value="$2"
  [[ -n "$value" ]] || die "$name is required"
  case "$value" in
    https://*) ;;
    http://localhost*|http://127.0.0.1*|http://[::1]*)
      ;;
    *)
      die "$name must use https:// (or localhost / 127.0.0.1 for local testing)"
      ;;
  esac
}

resolve_defaults() {
  case "$PROVIDER" in
    trustapi)
      PROVIDER_DISPLAY="TrustAPI"
      [[ "$ANTHROPIC_BASE_URL_EXPLICIT" == true ]] || ANTHROPIC_BASE_URL="$DEFAULT_TRUSTAPI_ANTHROPIC_BASE_URL"
      [[ "$OPENAI_BASE_URL_EXPLICIT" == true ]] || OPENAI_BASE_URL="$DEFAULT_TRUSTAPI_OPENAI_BASE_URL"
      [[ "$API_KEY_ENV_EXPLICIT" == true ]] || API_KEY_ENV="$DEFAULT_TRUSTAPI_API_KEY_ENV"
      [[ "$CODEX_PROFILE_EXPLICIT" == true ]] || CODEX_PROFILE="$DEFAULT_TRUSTAPI_CODEX_PROFILE"
      CODEX_PROVIDER_ID="trustapi"
      CODEX_MODEL="$DEFAULT_CODEX_MODEL"
      ;;
    vibediary)
      PROVIDER_DISPLAY="VibeDiary"
      [[ "$ANTHROPIC_BASE_URL_EXPLICIT" == true ]] || ANTHROPIC_BASE_URL="$DEFAULT_VIBEDIARY_ANTHROPIC_BASE_URL"
      [[ "$OPENAI_BASE_URL_EXPLICIT" == true ]] || OPENAI_BASE_URL="$DEFAULT_VIBEDIARY_OPENAI_BASE_URL"
      [[ "$API_KEY_ENV_EXPLICIT" == true ]] || API_KEY_ENV="$DEFAULT_VIBEDIARY_API_KEY_ENV"
      [[ "$CODEX_PROFILE_EXPLICIT" == true ]] || CODEX_PROFILE="$DEFAULT_VIBEDIARY_CODEX_PROFILE"
      CODEX_PROVIDER_ID="vibediary"
      CODEX_MODEL="$DEFAULT_CODEX_MODEL"
      ;;
    custom)
      PROVIDER_DISPLAY="Custom"
      [[ "$API_KEY_ENV_EXPLICIT" == true ]] || API_KEY_ENV="$DEFAULT_CUSTOM_API_KEY_ENV"
      [[ "$CODEX_PROFILE_EXPLICIT" == true ]] || CODEX_PROFILE="$DEFAULT_CUSTOM_CODEX_PROFILE"
      CODEX_PROVIDER_ID="$CODEX_PROFILE"
      CODEX_MODEL=""
      ;;
    *)
      die "unsupported provider: $PROVIDER"
      ;;
  esac
}

validate_configuration() {
  validate_env_name
  validate_codex_profile

  if uses_anthropic_base_url; then
    validate_url "--anthropic-base-url" "$ANTHROPIC_BASE_URL"
  fi
  if uses_openai_base_url; then
    validate_url "--openai-base-url" "$OPENAI_BASE_URL"
  fi
}

prompt_choice() {
  local prompt="$1"
  local default_value="$2"
  local choice=""
  printf '%s' "$prompt" >&2
  IFS= read -r choice || true
  choice="$(trim "$choice")"
  if [[ -z "$choice" ]]; then
    printf '%s' "$default_value"
  else
    printf '%s' "$choice"
  fi
}

prompt_language() {
  if [[ -n "$LANGUAGE" ]]; then
    return
  fi

  printf '\n[Step 1/6] Language / 语言\n'
  printf '%s\n' "  1) English"
  printf '%s\n' "  2) 中文"
  case "$(prompt_choice "$(printf '  %s' "Choice [1]: ")" "1")" in
    2)
      LANGUAGE="zh"
      ;;
    *)
      LANGUAGE="en"
      ;;
  esac
}

print_platform_step() {
  print_step "Step 2/6" "Platform" "平台"
  printf '  %s\n' "$(text "$OS_NAME $ARCH_NAME, $(basename "${SHELL:-unknown}")" "$OS_NAME $ARCH_NAME, $(basename "${SHELL:-unknown}")")"
}

prompt_provider() {
  if [[ "$PROVIDER_EXPLICIT" == true ]]; then
    return
  fi

  print_step "Step 3/6" "Choose Provider" "选择 Provider"
  printf '  1) VibeDiary\n'
  printf '  2) TrustAPI\n'
  printf '  3) Custom\n'
  case "$(prompt_choice "$(printf '  %s' "Choice [1]: ")" "1")" in
    2)
      PROVIDER="trustapi"
      ;;
    3)
      PROVIDER="custom"
      ;;
    *)
      PROVIDER="vibediary"
      ;;
  esac
}

prompt_custom_provider_inputs() {
  if [[ "$PROVIDER" != "custom" ]]; then
    return
  fi

  if [[ -z "$ANTHROPIC_BASE_URL" ]]; then
    printf '%s' "$(text "  Anthropic base URL: " "  Anthropic Base URL: ")" >&2
    IFS= read -r ANTHROPIC_BASE_URL || true
    ANTHROPIC_BASE_URL="$(trim "$ANTHROPIC_BASE_URL")"
  fi
  if [[ -z "$OPENAI_BASE_URL" ]]; then
    printf '%s' "$(text "  Responses base URL: " "  Responses Base URL: ")" >&2
    IFS= read -r OPENAI_BASE_URL || true
    OPENAI_BASE_URL="$(trim "$OPENAI_BASE_URL")"
  fi
  if [[ -z "$API_KEY_ENV" ]]; then
    printf '%s' "$(text "  API key env name [CUSTOM_API_KEY]: " "  API Key Env [CUSTOM_API_KEY]: ")" >&2
    IFS= read -r API_KEY_ENV || true
    API_KEY_ENV="$(trim "$API_KEY_ENV")"
    [[ -n "$API_KEY_ENV" ]] || API_KEY_ENV="$DEFAULT_CUSTOM_API_KEY_ENV"
  fi
  if [[ -z "$CODEX_PROFILE" ]]; then
    printf '%s' "$(text "  Codex profile [custom]: " "  Codex Profile [custom]: ")" >&2
    IFS= read -r CODEX_PROFILE || true
    CODEX_PROFILE="$(trim "$CODEX_PROFILE")"
    [[ -n "$CODEX_PROFILE" ]] || CODEX_PROFILE="$DEFAULT_CUSTOM_CODEX_PROFILE"
  fi
}

prompt_api_key() {
  print_step "Step 4/6" "API Key" "API Key"
  printf '%s' "$(text "  Enter API key: " "  输入 API Key: ")" >&2
  if [[ -t 0 ]]; then
    IFS= read -r -s API_KEY
    printf '\n' >&2
  else
    IFS= read -r API_KEY || true
  fi
  API_KEY="$(trim "$API_KEY")"
  [[ -n "$API_KEY" ]] || die "API key is required"
}

tool_label() {
  case "$1" in
    1) text "Claude Code CLI" "Claude Code CLI" ;;
    2) text "Claude Code (VS Code)" "Claude Code (VS Code)" ;;
    3) text "Codex CLI" "Codex CLI" ;;
    4) text "Codex (VS Code)" "Codex (VS Code)" ;;
    5) text "OpenClaw" "OpenClaw" ;;
    6) text "Cursor" "Cursor" ;;
  esac
}

tool_selected() {
  case "$1" in
    1) [[ "$SELECT_CLAUDE" == true ]] ;;
    2) [[ "$SELECT_CLAUDE_VSCODE" == true ]] ;;
    3) [[ "$SELECT_CODEX" == true ]] ;;
    4) [[ "$SELECT_CODEX_VSCODE" == true ]] ;;
    5) [[ "$SELECT_OPENCLAW" == true ]] ;;
    6) [[ "$SELECT_CURSOR" == true ]] ;;
  esac
}

tool_locked() {
  case "$1" in
    1) [[ "$SKIP_CLAUDE" == true ]] ;;
    2) [[ "$SKIP_CLAUDE_VSCODE" == true ]] ;;
    3) [[ "$SKIP_CODEX" == true ]] ;;
    4) [[ "$SKIP_CODEX_VSCODE" == true ]] ;;
    5) [[ "$SKIP_OPENCLAW" == true ]] ;;
    6) [[ "$SKIP_CURSOR" == true ]] ;;
  esac
}

tool_status() {
  case "$1" in
    1)
      if [[ "$DETECT_CLAUDE" == true ]]; then
        printf '%s' "${CLAUDE_VERSION:-detected}"
      else
        text "not found" "未安装"
      fi
      ;;
    2)
      if [[ "$DETECT_CLAUDE_VSCODE" == true ]]; then
        text "detected" "已检测"
      else
        text "not found" "未安装"
      fi
      ;;
    3)
      if [[ "$DETECT_CODEX" == true ]]; then
        printf '%s' "${CODEX_VERSION:-detected}"
      else
        text "not found" "未安装"
      fi
      ;;
    4)
      if [[ "$DETECT_CODEX_VSCODE" == true ]]; then
        text "detected" "已检测"
      else
        text "not found" "未安装"
      fi
      ;;
    5)
      if [[ "$DETECT_OPENCLAW" == true ]]; then
        printf '%s' "${OPENCLAW_VERSION:-detected}"
      else
        text "not found" "未安装"
      fi
      ;;
    6)
      if [[ "$DETECT_CURSOR" == true ]]; then
        printf '%s' "${CURSOR_VERSION:-detected}"
      else
        text "not found" "未安装"
      fi
      ;;
  esac
}

set_tool_selection() {
  local index="$1"
  local value="$2"
  case "$index" in
    1) SELECT_CLAUDE="$value" ;;
    2) SELECT_CLAUDE_VSCODE="$value" ;;
    3) SELECT_CODEX="$value" ;;
    4) SELECT_CODEX_VSCODE="$value" ;;
    5) SELECT_OPENCLAW="$value" ;;
    6) SELECT_CURSOR="$value" ;;
  esac
}

toggle_tool() {
  local index="$1"
  if tool_locked "$index"; then
    warn "$(text "skip flag keeps this target disabled" "该目标被 --skip-* 固定关闭")"
    return
  fi
  if tool_selected "$index"; then
    set_tool_selection "$index" false
  else
    set_tool_selection "$index" true
  fi
}

print_tool_selection() {
  local index mark
  for index in 1 2 3 4 5 6; do
    if tool_selected "$index"; then
      mark="x"
    else
      mark=" "
    fi
    printf '  %s) [%s] %s  %s\n' "$index" "$mark" "$(tool_label "$index")" "$(tool_status "$index")"
  done
}

prompt_tool_selection() {
  local choice=""
  print_step "Step 5/6" "Select Tools" "选择工具"
  while true; do
    print_tool_selection
    printf '%s' "$(text "  Toggle a tool by number, press Enter to confirm: " "  输入编号切换，直接回车确认: ")" >&2
    IFS= read -r choice || true
    choice="$(trim "$choice")"
    [[ -z "$choice" ]] && break
    case "$choice" in
      1|2|3|4|5|6)
        toggle_tool "$choice"
        ;;
      *)
        warn "$(text "enter a number between 1 and 6" "请输入 1 到 6 的编号")"
        ;;
    esac
  done
}

soft_check_preflight() {
  detect_tools
  apply_default_tool_selection
  if ! any_selected && [[ "$INTERACTIVE_MODE" == false ]]; then
    die "No supported tools found. Install at least one: claude, codex, openclaw, cursor"
  fi
}

backup_file() {
  local file="$1"
  local stamp
  [[ -f "$file" ]] || return 0
  mkdir -p "$BACKUP_DIR"
  stamp="$(date +%Y%m%d%H%M%S)"
  cp "$file" "$BACKUP_DIR/$(basename "$file").$stamp.bak"
}

strip_block() {
  local file="$1"
  local begin="$2"
  local end="$3"
  if [[ ! -f "$file" ]]; then
    return 0
  fi
  awk -v begin="$begin" -v end="$end" '
    $0 == begin {skip=1; next}
    $0 == end {skip=0; next}
    skip != 1 {print}
  ' "$file"
}

replace_block() {
  local file="$1"
  local begin="$2"
  local end="$3"
  local content="$4"
  local tmp

  mkdir -p "$(dirname "$file")"
  backup_file "$file"
  tmp="$(mktemp)"
  strip_block "$file" "$begin" "$end" > "$tmp"
  if [[ -s "$tmp" ]]; then
    printf '\n' >> "$tmp"
  fi
  printf '%s\n' "$begin" >> "$tmp"
  printf '%s\n' "$content" >> "$tmp"
  printf '%s\n' "$end" >> "$tmp"
  mv "$tmp" "$file"
}

remove_block_in_place() {
  local file="$1"
  local begin="$2"
  local end="$3"
  local tmp

  [[ -f "$file" ]] || return 0
  backup_file "$file"
  tmp="$(mktemp)"
  strip_block "$file" "$begin" "$end" > "$tmp"
  mv "$tmp" "$file"
}

render_env_content() {
  printf '# Managed by TrustAPI Setup. Re-run setup.sh to update.\n'
  printf 'export TRUSTAPI_SETUP_PROVIDER=%s\n' "$(shell_quote "$PROVIDER")"
  printf 'export TRUSTAPI_SETUP_PROVIDER_ID=%s\n' "$(shell_quote "$CODEX_PROVIDER_ID")"
  printf 'export TRUSTAPI_SETUP_CODEX_PROFILE=%s\n' "$(shell_quote "$CODEX_PROFILE")"
  printf 'export TRUSTAPI_SETUP_API_KEY_ENV=%s\n' "$(shell_quote "$API_KEY_ENV")"
  printf 'export %s=%s\n' "$API_KEY_ENV" "$(shell_quote "$API_KEY")"
  if [[ "$SELECT_CLAUDE" == true || "$SELECT_CURSOR" == true ]]; then
    printf 'export ANTHROPIC_BASE_URL=%s\n' "$(shell_quote "$ANTHROPIC_BASE_URL")"
    printf 'export ANTHROPIC_API_KEY="$%s"\n' "$API_KEY_ENV"
  fi
}

render_shell_block() {
  printf 'if [ -f %s ]; then\n' "$(shell_quote "$ENV_FILE")"
  printf '  . %s\n' "$(shell_quote "$ENV_FILE")"
  printf 'fi\n'
}

render_codex_block() {
  printf '[model_providers.%s]\n' "$CODEX_PROVIDER_ID"
  printf 'name = %s\n' "$(toml_quote "$PROVIDER_DISPLAY")"
  printf 'base_url = %s\n' "$(toml_quote "$OPENAI_BASE_URL")"
  printf 'env_key = %s\n' "$(toml_quote "$API_KEY_ENV")"
  printf 'wire_api = "responses"\n\n'
  printf '[profiles.%s]\n' "$CODEX_PROFILE"
  printf 'model_provider = %s\n' "$(toml_quote "$CODEX_PROVIDER_ID")"
  if [[ -n "$CODEX_MODEL" ]]; then
    printf 'model = %s\n' "$(toml_quote "$CODEX_MODEL")"
  fi
}

render_claude_settings_snippet() {
  python3 - "$ANTHROPIC_BASE_URL" "$API_KEY" <<'PY'
import json
import sys

print(json.dumps({
    "env": {
        "ANTHROPIC_BASE_URL": sys.argv[1],
        "ANTHROPIC_API_KEY": sys.argv[2],
    }
}, ensure_ascii=False, indent=2))
PY
}

render_openclaw_commands() {
  local api_ref=""
  api_ref="\${"
  api_ref+="$API_KEY_ENV"
  api_ref+="}"
  printf 'openclaw config set "models.providers.%s.baseUrl" %s\n' "$CODEX_PROVIDER_ID" "$(shell_quote "$ANTHROPIC_BASE_URL")"
  printf 'openclaw config set "models.providers.%s.apiKey" %s\n' "$CODEX_PROVIDER_ID" "$(shell_quote "$api_ref")"
  printf 'openclaw config set "models.providers.%s.api" "anthropic-messages"\n' "$CODEX_PROVIDER_ID"
  printf 'openclaw config set "models.mode" "merge"\n'
}

write_env_file() {
  local tmp
  mkdir -p "$ENV_DIR"
  backup_file "$ENV_FILE"
  tmp="$(mktemp)"
  render_env_content > "$tmp"
  chmod 600 "$tmp"
  mv "$tmp" "$ENV_FILE"
  chmod 600 "$ENV_FILE"
}

write_shell_profile() {
  replace_block "$SELECTED_SHELL_PROFILE" "$SHELL_MARKER_BEGIN" "$SHELL_MARKER_END" "$(render_shell_block)"
}

write_codex_config() {
  replace_block "$CODEX_CONFIG" "$CODEX_MARKER_BEGIN" "$CODEX_MARKER_END" "$(render_codex_block)"
}

merge_claude_settings_env() {
  mkdir -p "$(dirname "$CLAUDE_SETTINGS")"
  backup_file "$CLAUDE_SETTINGS"
  python3 - "$CLAUDE_SETTINGS" "$ANTHROPIC_BASE_URL" "$API_KEY" <<'PY'
import json
import pathlib
import sys

path = pathlib.Path(sys.argv[1])
base_url = sys.argv[2]
api_key = sys.argv[3]

data = {}
if path.exists():
    raw = path.read_text(encoding="utf-8").strip()
    if raw:
        data = json.loads(raw)

if not isinstance(data, dict):
    raise SystemExit("Claude settings root must be a JSON object")

env = data.get("env")
if env is None:
    env = {}
if not isinstance(env, dict):
    env = {}

env["ANTHROPIC_BASE_URL"] = base_url
env["ANTHROPIC_API_KEY"] = api_key
data["env"] = env
path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
PY
}

remove_claude_settings_env() {
  [[ -f "$CLAUDE_SETTINGS" ]] || return 0
  backup_file "$CLAUDE_SETTINGS"
  python3 - "$CLAUDE_SETTINGS" <<'PY'
import json
import pathlib
import sys

path = pathlib.Path(sys.argv[1])
raw = path.read_text(encoding="utf-8").strip()
if not raw:
    raise SystemExit(0)

data = json.loads(raw)
if not isinstance(data, dict):
    raise SystemExit(0)

env = data.get("env")
if isinstance(env, dict):
    env.pop("ANTHROPIC_BASE_URL", None)
    env.pop("ANTHROPIC_API_KEY", None)
    if env:
      data["env"] = env
    else:
      data.pop("env", None)

path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
PY
}

write_openclaw_config() {
  local api_ref=""
  if ! have_command openclaw; then
    warn "openclaw not found, skipping OpenClaw config"
    return 0
  fi

  api_ref="\${"
  api_ref+="$API_KEY_ENV"
  api_ref+="}"

  openclaw config set "models.providers.${CODEX_PROVIDER_ID}.baseUrl" "$ANTHROPIC_BASE_URL"
  openclaw config set "models.providers.${CODEX_PROVIDER_ID}.apiKey" "$api_ref"
  openclaw config set "models.providers.${CODEX_PROVIDER_ID}.api" "anthropic-messages"
  openclaw config set "models.mode" "merge"
}

selected_tools_summary() {
  local items=()
  [[ "$SELECT_CLAUDE" == true ]] && items+=("$(tool_label 1)")
  [[ "$SELECT_CLAUDE_VSCODE" == true ]] && items+=("$(tool_label 2)")
  [[ "$SELECT_CODEX" == true ]] && items+=("$(tool_label 3)")
  [[ "$SELECT_CODEX_VSCODE" == true ]] && items+=("$(tool_label 4)")
  [[ "$SELECT_OPENCLAW" == true ]] && items+=("$(tool_label 5)")
  [[ "$SELECT_CURSOR" == true ]] && items+=("$(tool_label 6)")
  local IFS=", "
  printf '%s' "${items[*]}"
}

print_plan() {
  printf '== %s %s ==\n' "$PROGRAM_NAME" "$VERSION"
  printf 'provider: %s\n' "$PROVIDER"
  printf 'language: %s\n' "${LANGUAGE:-$DEFAULT_LANGUAGE}"
  printf 'platform: %s %s\n' "$OS_NAME" "$ARCH_NAME"
  printf 'env-file: %s\n' "$ENV_FILE"
  printf 'shell-profile: %s\n' "$SELECTED_SHELL_PROFILE"
  printf 'selected-tools: %s\n' "$(selected_tools_summary)"
}

print_generated_content() {
  echo
  echo '--- env.sh ---'
  render_env_content
  echo
  echo '--- shell block ---'
  render_shell_block
  if uses_openai_base_url; then
    echo
    echo '--- codex config block ---'
    render_codex_block
  fi
  if [[ "$SELECT_CLAUDE_VSCODE" == true ]]; then
    echo
    echo '--- claude settings env ---'
    render_claude_settings_snippet
  fi
  if [[ "$SELECT_OPENCLAW" == true ]]; then
    echo
    echo '--- openclaw commands ---'
    render_openclaw_commands
  fi
}

print_verify_commands() {
  echo
  echo 'Next steps:'
  printf '1. source %s\n' "$SELECTED_SHELL_PROFILE"
  printf '2. curl -fsSL https://vibediary.app/trustapi-setup/verify.sh | bash -s -- --codex-profile %s\n' "$CODEX_PROFILE"
  if [[ "$SELECT_CODEX_VSCODE" == true ]]; then
    echo '3. Launch VS Code from a terminal so the shared Codex env var is available.'
  fi
  if [[ "$SELECT_CURSOR" == true ]]; then
    echo '4. Restart Cursor so it reloads the shell env.'
  fi
}

parse_provider_id_from_codex_block() {
  [[ -f "$CODEX_CONFIG" ]] || return 0
  awk -v begin="$CODEX_MARKER_BEGIN" -v end="$CODEX_MARKER_END" '
    $0 == begin {capture=1; next}
    $0 == end {capture=0}
    capture == 1 {print}
  ' "$CODEX_CONFIG" | sed -n 's/^\[model_providers\.\(.*\)\]$/\1/p' | head -n 1
}

load_managed_metadata() {
  local managed_provider_id=""
  if [[ -f "$ENV_FILE" ]]; then
    # shellcheck disable=SC1090
    source "$ENV_FILE"
    managed_provider_id="${TRUSTAPI_SETUP_PROVIDER_ID:-}"
    [[ -n "$managed_provider_id" ]] && CODEX_PROVIDER_ID="$managed_provider_id"
  fi
  if [[ -z "$CODEX_PROVIDER_ID" ]]; then
    CODEX_PROVIDER_ID="$(parse_provider_id_from_codex_block)"
  fi
}

uninstall_config() {
  local candidates=()
  local file

  load_managed_metadata
  [[ -n "$SHELL_PROFILE" ]] && candidates+=("$SHELL_PROFILE")
  candidates+=("$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile")

  for file in "${candidates[@]}"; do
    remove_block_in_place "$file" "$SHELL_MARKER_BEGIN" "$SHELL_MARKER_END"
  done

  remove_block_in_place "$CODEX_CONFIG" "$CODEX_MARKER_BEGIN" "$CODEX_MARKER_END"
  remove_claude_settings_env

  if [[ -n "$CODEX_PROVIDER_ID" ]] && have_command openclaw; then
    openclaw config unset "models.providers.${CODEX_PROVIDER_ID}" || warn "failed to unset OpenClaw provider ${CODEX_PROVIDER_ID}"
  fi

  rm -f "$ENV_FILE"
  info "removed managed TrustAPI Setup config"
}

run_interactive_wizard() {
  INTERACTIVE_MODE=true
  prompt_language
  print_platform_step
  prompt_provider
  prompt_custom_provider_inputs
  resolve_defaults
  prompt_api_key
  prompt_tool_selection
}

main() {
  parse_args "$@"
  validate_lang
  detect_platform
  resolve_paths
  pick_shell_profile

  if [[ "$UNINSTALL" == true ]]; then
    if [[ -z "$LANGUAGE" ]]; then
      LANGUAGE="$DEFAULT_LANGUAGE"
    fi
    resolve_defaults
    uninstall_config
    exit 0
  fi

  if [[ -n "$API_KEY" && -z "$LANGUAGE" ]]; then
    LANGUAGE="$DEFAULT_LANGUAGE"
  fi

  soft_check_preflight

  if [[ -z "$API_KEY" ]]; then
    run_interactive_wizard
  else
    resolve_defaults
  fi

  resolve_defaults
  if ! any_selected; then
    die "No supported tools found. Install at least one: claude, codex, openclaw, cursor"
  fi
  validate_configuration
  print_step "Step 6/6" "Write Config" "写入配置"
  print_plan

  if [[ "$PRINT_ONLY" == true ]]; then
    print_generated_content
    exit 0
  fi

  write_env_file
  write_shell_profile
  if [[ "$SELECT_CODEX" == true || "$SELECT_CODEX_VSCODE" == true ]]; then
    write_codex_config
  fi
  if [[ "$SELECT_CLAUDE_VSCODE" == true ]]; then
    merge_claude_settings_env
  fi
  if [[ "$SELECT_OPENCLAW" == true ]]; then
    write_openclaw_config
  fi

  info "wrote managed config to $ENV_FILE"
  print_verify_commands
}

main "$@"
