#!/usr/bin/env bash

################################################################################
# 闪电API - OpenClaw 一键配置脚本
#
# 功能: 选择线路 / 选择模型类型 / 拉取模型列表 / 写入 OpenClaw 配置
# 官网: flashapi.top
# 模型调用: ai.flashapi.top (国内直连) / cdn.flashapi.top (海外CDN)
################################################################################

set -euo pipefail
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
GRAY='\033[0;90m'
BOLD='\033[1m'
BLUE='\033[38;5;33m'
BRIGHT_YELLOW='\033[38;5;226m'
NC='\033[0m'

OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
OPENCLAW_CONFIG_FILE="$OPENCLAW_CONFIG_DIR/openclaw.json"
AUTH_PROFILES_FILE="$OPENCLAW_CONFIG_DIR/agents/main/agent/auth-profiles.json"

ROUTE_LABEL=""
ROUTE_BASE_URL=""
MODEL_LABEL=""
PROVIDER=""
PROVIDER_API=""
PROVIDER_BASE_URL=""
MODEL_KEY=""
MODEL_ID=""
API_KEY=""
MODELS_PAYLOAD=""

print_banner() {
  echo ""
  echo -e "  ${BOLD}${BRIGHT_YELLOW}    ⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}  ███████╗██╗      █████╗ ███████╗██╗  ██╗${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}  ██╔════╝██║     ██╔══██╗██╔════╝██║  ██║${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}  █████╗  ██║     ███████║███████╗███████║${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}  ██╔══╝  ██║     ██╔══██║╚════██║██╔══██║${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}  ██║     ███████╗██║  ██║███████║██║  ██║${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}  ╚═╝     ╚══════╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝${NC}"
  echo -e "  ${BOLD}${BLUE}           ⚡ A P I ⚡${NC}"
  echo -e "  ${BOLD}${BRIGHT_YELLOW}    ⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡⚡${NC}"
  echo ""
  echo -e "  ${GRAY}───────────────────────────────────────────────────────${NC}"
  echo -e "  ${WHITE}⚡ 闪电API${NC} ${GRAY}|${NC} ${CYAN}官网${NC} ${BOLD}${BRIGHT_YELLOW}flashapi.top${NC}"
  echo -e "  ${WHITE}OpenClaw 一键配置${NC} ${GRAY}|${NC} ${CYAN}让顶尖模型触手可及${NC}"
  echo -e "  ${GRAY}───────────────────────────────────────────────────────${NC}"
  echo -e "  ${GRAY}国内直连:${NC} ${GREEN}ai.flashapi.top${NC}  ${GRAY}海外CDN:${NC} ${GREEN}cdn.flashapi.top${NC}"
  echo -e "  ${GRAY}───────────────────────────────────────────────────────${NC}"
  echo ""
}

print_status() {
  local type="$1"
  local message="$2"
  case "$type" in
    ok)    echo -e "  ${GREEN}[⚡]${NC} $message" ;;
    info)  echo -e "  ${CYAN}[*]${NC} $message" ;;
    warn)  echo -e "  ${YELLOW}[!]${NC} $message" ;;
    error) echo -e "  ${RED}[x]${NC} $message" ;;
    *)     echo "  $message" ;;
  esac
}

require_commands() {
  if ! command -v node >/dev/null 2>&1; then
    print_status "error" "未检测到 Node.js，无法安全修改 JSON 配置"
    exit 1
  fi
  if ! command -v curl >/dev/null 2>&1; then
    print_status "error" "未检测到 curl，无法拉取模型列表"
    exit 1
  fi
}

mask_key() {
  local value="$1"
  if [[ -z "$value" ]]; then
    echo ""
    return
  fi
  if [[ ${#value} -le 12 ]]; then
    echo "$value"
    return
  fi
  echo "${value:0:8}...${value: -4}"
}

choose_route() {
  echo -e "  ${WHITE}请选择 API 线路:${NC}"
  echo ""
  echo -e "    ${BRIGHT_YELLOW}⚡${NC} ${CYAN}1)${NC} ${GREEN}国内直连${NC} - https://ai.flashapi.top"
  echo -e "       ${GRAY}服务器位于香港，国内可直连${NC}"
  echo ""
  echo -e "    ${BRIGHT_YELLOW}⚡${NC} ${CYAN}2)${NC} ${GREEN}海外CDN${NC}  - https://cdn.flashapi.top"
  echo -e "       ${GRAY}全球 CDN 加速，适合海外用户${NC}"
  echo ""
  echo -en "  ${WHITE}请输入选项 (1/2): ${NC}" >&2

  local choice
  read -r choice < /dev/tty

  case "$choice" in
    1)
      ROUTE_LABEL="国内直连"
      ROUTE_BASE_URL="https://ai.flashapi.top"
      ;;
    2)
      ROUTE_LABEL="海外CDN"
      ROUTE_BASE_URL="https://cdn.flashapi.top"
      ;;
    *)
      print_status "error" "无效线路选项，已取消"
      exit 1
      ;;
  esac

  echo ""
  print_status "ok" "已选择线路: ${ROUTE_LABEL} (${ROUTE_BASE_URL})"
}

choose_model_type() {
  echo ""
  echo -e "  ${WHITE}请选择模型类型:${NC}"
  echo ""
  echo -e "    ${BRIGHT_YELLOW}⚡${NC} ${CYAN}1)${NC} ${GREEN}GPT${NC}"
  echo -e "       ${GRAY}自动筛选 OpenAI / GPT 系列模型${NC}"
  echo ""
  echo -e "    ${BRIGHT_YELLOW}⚡${NC} ${CYAN}2)${NC} ${GREEN}Claude${NC}"
  echo -e "       ${GRAY}自动筛选 Anthropic / Claude 系列模型${NC}"
  echo ""
  echo -en "  ${WHITE}请输入选项 (1/2): ${NC}" >&2

  local choice
  read -r choice < /dev/tty

  case "$choice" in
    1)
      MODEL_LABEL="GPT"
      PROVIDER="openai"
      PROVIDER_API="openai-responses"
      PROVIDER_BASE_URL="${ROUTE_BASE_URL}/v1"
      ;;
    2)
      MODEL_LABEL="Claude"
      PROVIDER="anthropic"
      PROVIDER_API=""
      PROVIDER_BASE_URL="${ROUTE_BASE_URL}"
      ;;
    *)
      print_status "error" "无效模型类型，已取消"
      exit 1
      ;;
  esac

  echo ""
  print_status "ok" "已选择模型类型: ${MODEL_LABEL}"
}

read_api_key() {
  echo ""
  echo -en "  ${WHITE}请输入 API Key: ${NC}" >&2

  local value=""
  while IFS= read -r -s -n1 char < /dev/tty; do
    if [[ "$char" == $'\0' || "$char" == $'\n' || "$char" == $'\r' ]]; then
      break
    elif [[ "$char" == $'\177' || "$char" == $'\b' ]]; then
      if [[ -n "$value" ]]; then
        value="${value%?}"
        echo -en "\b \b" >&2
      fi
    else
      value+="$char"
      echo -n "*" >&2
    fi
  done
  echo "" >&2

  if [[ -z "$value" ]]; then
    print_status "error" "API Key 不能为空，已取消"
    exit 1
  fi

  API_KEY="$value"
  print_status "info" "已读取 API Key: $(mask_key "$API_KEY")"
}

fetch_models() {
  echo ""
  print_status "info" "正在拉取模型列表并验证连通性 ..."

  local response
  response="$(
    curl -sS --max-time 20 \
      -H "Authorization: Bearer ${API_KEY}" \
      -H "x-api-key: ${API_KEY}" \
      -H "anthropic-version: 2023-06-01" \
      "${ROUTE_BASE_URL}/v1/models" 2>/dev/null || true
  )"

  if [[ -z "$response" ]]; then
    response="$(
      curl -sS --max-time 20 \
        -H "Authorization: Bearer ${API_KEY}" \
        -H "x-api-key: ${API_KEY}" \
        -H "anthropic-version: 2023-06-01" \
        "${ROUTE_BASE_URL}/models" 2>/dev/null || true
    )"
  fi

  if [[ -z "$response" ]]; then
    print_status "error" "模型列表请求失败，未收到返回内容"
    exit 1
  fi

  MODELS_PAYLOAD="$response"

  if ! printf '%s' "$MODELS_PAYLOAD" | node -e '
const fs = require("fs");
const raw = fs.readFileSync(0, "utf8").trim();
if (!raw) process.exit(1);
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== "object") process.exit(1);
' >/dev/null 2>&1; then
    print_status "error" "接口返回不是合法 JSON，无法解析模型列表"
    exit 1
  fi

  print_status "ok" "模型列表请求成功"
}

choose_model_from_remote() {
  print_status "info" "正在筛选 ${MODEL_LABEL} 模型 ..."

  local selection
  selection="$(
    printf '%s' "$MODELS_PAYLOAD" | PROVIDER="$PROVIDER" node -e '
const fs = require("fs");
const provider = process.env.PROVIDER;
const raw = fs.readFileSync(0, "utf8");
const parsed = JSON.parse(raw);
const list = Array.isArray(parsed?.data)
  ? parsed.data
  : Array.isArray(parsed?.models)
    ? parsed.models
    : Array.isArray(parsed)
      ? parsed
      : [];

function getId(item) {
  if (typeof item === "string") return item;
  if (!item || typeof item !== "object") return "";
  return String(item.id || item.name || item.model || "").trim();
}

function matches(id, providerName) {
  const value = id.toLowerCase();
  if (!value) return false;
  if (providerName === "openai") {
    return value.startsWith("openai/")
      || value.startsWith("gpt-")
      || value.startsWith("chatgpt-")
      || value.startsWith("o1")
      || value.startsWith("o3")
      || value.startsWith("o4")
      || value.includes("codex");
  }
  if (providerName === "anthropic") {
    return value.startsWith("anthropic/") || value.includes("claude");
  }
  return false;
}

function normalize(id, providerName) {
  if (id.includes("/")) return id;
  return `${providerName}/${id}`;
}

const results = [];
const seen = new Set();

for (const item of list) {
  const id = getId(item);
  if (!matches(id, provider)) continue;
  const modelKey = normalize(id, provider);
  const modelId = modelKey.split("/").slice(1).join("/");
  if (seen.has(modelKey)) continue;
  seen.add(modelKey);
  results.push({ modelKey, modelId });
}

if (results.length === 0) {
  process.exit(2);
}

for (const item of results) {
  process.stdout.write(`${item.modelKey}\t${item.modelId}\n`);
}
' 2>/dev/null
  )"

  if [[ -z "$selection" ]]; then
    print_status "error" "接口里没有筛选到 ${MODEL_LABEL} 模型"
    exit 1
  fi

  MODEL_ROWS=()
  while IFS= read -r line; do
    MODEL_ROWS+=("$line")
  done <<<"$selection"

  echo ""
  echo -e "  ${WHITE}请选择具体模型:${NC}"
  echo ""

  local i=1
  local row key id
  for row in "${MODEL_ROWS[@]}"; do
    key="${row%%$'\t'*}"
    id="${row#*$'\t'}"
    echo -e "    ${BRIGHT_YELLOW}⚡${NC} ${CYAN}${i})${NC} ${GREEN}${id}${NC}"
    echo -e "       ${GRAY}${key}${NC}"
    echo ""
    i=$((i + 1))
  done

  echo -en "  ${WHITE}请输入模型编号: ${NC}" >&2
  local choice
  read -r choice < /dev/tty

  if ! [[ "$choice" =~ ^[0-9]+$ ]]; then
    print_status "error" "模型编号无效"
    exit 1
  fi

  if (( choice < 1 || choice > ${#MODEL_ROWS[@]} )); then
    print_status "error" "模型编号超出范围"
    exit 1
  fi

  row="${MODEL_ROWS[$((choice - 1))]}"
  MODEL_KEY="${row%%$'\t'*}"
  MODEL_ID="${row#*$'\t'}"

  print_status "ok" "已选择模型: ${MODEL_KEY}"
}

confirm_write() {
  echo ""
  print_status "info" "即将写入 OpenClaw 配置"
  echo ""
  echo -e "    ${WHITE}线路:${NC} ${GREEN}${ROUTE_LABEL}${NC}"
  echo -e "    ${WHITE}接口:${NC} ${GREEN}${ROUTE_BASE_URL}${NC}"
  echo -e "    ${WHITE}类型:${NC} ${GREEN}${MODEL_LABEL}${NC}"
  echo -e "    ${WHITE}Provider:${NC} ${GREEN}${PROVIDER}${NC}"
  echo -e "    ${WHITE}模型:${NC} ${GREEN}${MODEL_KEY}${NC}"
  echo -e "    ${WHITE}API Key:${NC} ${GREEN}$(mask_key "$API_KEY")${NC}"
  echo ""
  echo -en "  ${YELLOW}确认写入配置? (y/N): ${NC}" >&2

  local answer
  read -r answer < /dev/tty
  if [[ "$answer" != "y" && "$answer" != "Y" ]]; then
    print_status "warn" "已取消配置"
    exit 0
  fi
}

write_config() {
  mkdir -p "$OPENCLAW_CONFIG_DIR"

  if [[ -f "$OPENCLAW_CONFIG_FILE" ]]; then
    cp "$OPENCLAW_CONFIG_FILE" "$OPENCLAW_CONFIG_FILE.bak"
    print_status "info" "已备份原配置到 $OPENCLAW_CONFIG_FILE.bak"
  fi

  CONFIG_FILE="$OPENCLAW_CONFIG_FILE" \
  AUTH_FILE="$AUTH_PROFILES_FILE" \
  PROVIDER="$PROVIDER" \
  MODEL_KEY="$MODEL_KEY" \
  MODEL_ID="$MODEL_ID" \
  PROVIDER_BASE_URL="$PROVIDER_BASE_URL" \
  PROVIDER_API="$PROVIDER_API" \
  API_KEY="$API_KEY" \
  node <<'NODE'
const fs = require("fs");
const path = require("path");

const configFile = process.env.CONFIG_FILE;
const authFile = process.env.AUTH_FILE;
const provider = process.env.PROVIDER;
const modelKey = process.env.MODEL_KEY;
const modelId = process.env.MODEL_ID;
const providerBaseUrl = process.env.PROVIDER_BASE_URL;
const providerApi = process.env.PROVIDER_API;
const apiKey = process.env.API_KEY;

function readJson(file, fallback) {
  if (!fs.existsSync(file)) {
    return fallback;
  }
  try {
    return JSON.parse(fs.readFileSync(file, "utf8"));
  } catch {
    return fallback;
  }
}

function writeJson(file, data) {
  fs.mkdirSync(path.dirname(file), { recursive: true });
  fs.writeFileSync(file, `${JSON.stringify(data, null, 2)}\n`, "utf8");
}

const config = readJson(configFile, {});

config.models ??= {};
config.models.mode = "merge";
config.models.providers ??= {};

const providerConfig = {
  ...(config.models.providers[provider] ?? {}),
  baseUrl: providerBaseUrl,
  models: [{ id: modelId, name: modelId }],
  apiKey,
};

if (providerApi) {
  providerConfig.api = providerApi;
} else {
  delete providerConfig.api;
}

config.models.providers[provider] = providerConfig;

config.agents ??= {};
config.agents.defaults ??= {};
config.agents.defaults.model ??= {};
config.agents.defaults.model.primary = modelKey;

config.meta ??= {};
config.meta.lastTouchedAt = new Date().toISOString();

writeJson(configFile, config);

const auth = readJson(authFile, { version: 1, profiles: {} });
if (auth && auth.profiles && typeof auth.profiles === "object") {
  delete auth.profiles[`${provider}:default`];
  writeJson(authFile, auth);
}
NODE
}

show_result() {
  echo ""
  print_status "ok" "OpenClaw 配置已更新"
  echo -e "    ${WHITE}配置文件:${NC} ${GREEN}${OPENCLAW_CONFIG_FILE}${NC}"
  echo -e "    ${WHITE}Provider:${NC} ${GREEN}${PROVIDER}${NC}"
  echo -e "    ${WHITE}Base URL:${NC} ${GREEN}${PROVIDER_BASE_URL}${NC}"
  echo -e "    ${WHITE}Model:${NC} ${GREEN}${MODEL_KEY}${NC}"
  echo ""
  print_status "info" "如果 OpenClaw 正在运行，建议重启相关进程后再使用"
}

main() {
  print_banner
  require_commands
  choose_route
  choose_model_type
  read_api_key
  fetch_models
  choose_model_from_remote
  confirm_write
  write_config
  show_result
}

main "$@"
