#!/usr/bin/env bash
set -u
# ============================================================
#  FastAPI 高性能 API 实战 一键脚本（macOS / Linux / WSL）
#  公开源码，欢迎审查 —— 不放心可先复制给 AI 判断
#  功能：检测网络 → 建虚拟环境 → 安装 FastAPI → 生成 main.py
#        → 启动服务 → 验证 /docs 200
#  默认配置：云间 API 中转站（https://cloudzone-api.cyou/）
# ============================================================

GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
info()  { echo -e "${GREEN}[INFO]${NC} $1"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
step()  { echo -e "${CYAN}[STEP]${NC} $1"; }

detect_network() {
  step "检测网络环境（国内 / 国外）..."
  if curl -fsI --max-time 5 "https://claude.ai" >/dev/null 2>&1; then
    info "可直连 claude.ai，判定为海外网络"
    echo "overseas"
  else
    warn "无法直连 claude.ai，判定为国内网络环境（将自动切换镜像源）"
    echo "domestic"
  fi
}

check_python3() {
  step "检查 Python 3（要求 3.8+）..."
  local py=""
  for p in python3 python; do
    if command -v "$p" >/dev/null 2>&1; then
      local ver
      ver=$("$p" --version 2>&1)
      if echo "$ver" | grep -qE "3\.(8|9|[1-9][0-9])"; then
        py="$p"; break
      fi
    fi
  done
  if [ -n "$py" ]; then
    info "找到 $py ：$($py --version 2>&1)"
    return 0
  fi
  error "未找到 Python 3.8+。请先安装：https://www.python.org/downloads/"
  return 1
}

setup_venv() {
  step "创建虚拟环境 ..."
  mkdir -p fastapi-app && cd fastapi-app || return 1
  if [ -d ".venv" ]; then
    info "虚拟环境已存在，跳过创建"
  else
    "$PY" -m venv .venv || { error "创建虚拟环境失败"; return 1; }
    info "虚拟环境创建完成 (.venv)"
  fi
  # shellcheck disable=SC1091
  source .venv/bin/activate || { error "激活虚拟环境失败"; return 1; }
  info "虚拟环境已激活"
  return 0
}

install_fastapi() {
  local net="$1"
  step "安装 FastAPI（含 uvicorn）..."

  # 选 pip 镜像源
  local extra=""
  if [ "$net" = "domestic" ]; then
    extra="-i https://pypi.tuna.tsinghua.edu.cn/simple"
    info "使用清华 PyPI 镜像（国内快）"
  fi

  # 第 1 步：清华/阿里镜像
  if [ -n "$extra" ] && pip install "fastapi[standard]" $extra --timeout 120 >/dev/null 2>&1; then
    info "FastAPI 安装成功（镜像源）"
    return 0
  fi

  # 第 2 步：官方源
  info "镜像源不可用，尝试官方源（可能较慢，请耐心）..."
  if pip install "fastapi[standard]" --timeout 120 >/dev/null 2>&1; then
    info "FastAPI 安装成功（官方源）"
    return 0
  fi

  error "FastAPI 安装失败。请手动执行："
  echo "  pip install \"fastapi[standard]\" -i https://pypi.tuna.tsinghua.edu.cn/simple"
  echo "  （国内）或"
  echo "  pip install \"fastapi[standard]\""
  echo "  （海外）"
  return 1
}

generate_main_py() {
  step "生成 main.py（含 LLM 聊天接口）..."
  cat > main.py << 'MAINEOF'
"""
FastAPI 版本的 LLM 聊天接口示例
兼容 OpenAI /v1/chat/completions 协议
"""

import os
import random
import time
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI(title="LLM Chat API Demo")


class ChatMessage(BaseModel):
    role: str       # "user" 或 "assistant"
    content: str    # 消息内容


class ChatCompletionRequest(BaseModel):
    model: str                                    # 模型名称
    messages: list[ChatMessage]                   # 对话历史
    temperature: float = 0.7                      # 随机性 0~2
    max_tokens: int = 512                         # 最大回复长度


class Choice(BaseModel):
    index: int
    message: ChatMessage
    finish_reason: str = "stop"


class ChatCompletionResponse(BaseModel):
    id: str
    object: str = "chat.completion"
    created: int
    model: str
    choices: list[Choice]


def generate_response(prompt: str, model_name: str, temperature: float) -> str:
    """
    通过 OpenAI 兼容 API 调用真实大模型。

    优先读取环境变量 OPENAI_API_KEY（SDK 约定变量名）。
    base_url 默认 https://cloudzone-api.cyou/v1（云间 API 中转站），
    也可通过 OPENAI_BASE_URL 覆盖（如 OpenAI 官方、本地 Ollama 等）。

    未配置 Key 时 fallback 到模拟回复，并在控制台输出提示。
    """
    api_key = os.environ.get("OPENAI_API_KEY", "")
    if api_key:
        from openai import OpenAI
        base_url = os.environ.get("OPENAI_BASE_URL", "https://cloudzone-api.cyou/v1")
        client = OpenAI(api_key=api_key, base_url=base_url)
        try:
            resp = client.chat.completions.create(
                model=model_name,
                messages=[{"role": "user", "content": prompt}],
                temperature=temperature,
                max_tokens=512,
            )
            return resp.choices[0].message.content
        except Exception as e:
            print(f"[WARN] API 调用失败: {e}，切换为模拟回复")
    else:
        print("[INFO] 未设置 OPENAI_API_KEY，返回模拟回复。"
              "如需真实 AI 回复，请注册云间 API 中转站 "
              "(https://cloudzone-api.cyou/) 获取 Key，"
              "然后执行: export OPENAI_API_KEY='sk-xxx'")

    # 无 Key 或 API 失败：Mock 回退
    return f"(\u6a21\u62df\u56de\u590d) \u4f60\u95ee\u7684\u662f\u300c{prompt[:20]}...\u300d\uff0c\u8fd9\u662f\u4e00\u4e2a\u597d\u95ee\u9898\uff01"




@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
async def chat_completion(req: ChatCompletionRequest):
    user_msgs = [m for m in req.messages if m.role == "user"]
    if not user_msgs:
        raise HTTPException(status_code=400, detail="至少需要一条 user 消息")
    reply = generate_response(user_msgs[-1].content, req.model, req.temperature)
    return ChatCompletionResponse(
        id=f"chatcmpl-{int(time.time())}-{random.randint(1000, 9999)}",
        created=int(time.time()),
        model=req.model,
        choices=[Choice(index=0, message=ChatMessage(role="assistant", content=reply))],
    )


@app.get("/health")
async def health_check():
    return {"status": "ok", "service": "llm-chat-demo"}
MAINEOF
  info "main.py 已生成"
}

configure_api() {
  step "配置 API Key（用于对接 LLM）..."
  echo ""
  echo "是否使用云间 API 中转站作为默认模型源？"
  echo "  支持 OpenAI 兼容 + Anthropic 兼容、90+ 模型、国内直连、0.05x 起"
  echo ""
  echo "是否现在跳转注册并获取 API Key？"
  echo "  Y - 立即跳转至 https://cloudzone-api.cyou"
  echo "  N - 我已有 Key，自行输入"
  read -r -p "请选择 [Y/N]: " choice

  local API_KEY=""
  if [ "${choice:-N}" = "Y" ] || [ "${choice:-N}" = "y" ]; then
    info "正在打开浏览器..."
    if command -v xdg-open >/dev/null 2>&1; then
      xdg-open "https://cloudzone-api.cyou" >/dev/null 2>&1
    elif command -v open >/dev/null 2>&1; then
      open "https://cloudzone-api.cyou" >/dev/null 2>&1
    else
      warn "无法自动打开浏览器，请手动访问：https://cloudzone-api.cyou"
    fi
    echo "注册后在「我的 API Key」页面复制 Key（以 sk- 开头）。"
    read -r -p "粘贴你的 API Key: " API_KEY
  else
    read -r -s -p "请输入你的 API Key (sk-...): " API_KEY
    echo
  fi

  if [ -z "${API_KEY:-}" ]; then
    warn "未输入 API Key，后续需在 main.py 中手动修改。"
    return 0
  fi

  export OPENAI_API_KEY="$API_KEY"
  export OPENAI_BASE_URL="https://cloudzone-api.cyou/v1"
  info "API Key 已记录（当前会话）：${API_KEY:0:8}********"
  info "Base URL : https://cloudzone-api.cyou/v1"
  warn "新开终端后需重新输入，或将其写入 ~/.bashrc / ~/.zshrc"
}

run_service() {
  step "启动 FastAPI 服务（按 Ctrl+C 停止）..."
  echo ""
  info "以下地址可用："
  echo "  API:     http://127.0.0.1:8000/"
  echo "  文档:    http://127.0.0.1:8000/docs"
  echo "  ReDoc:   http://127.0.0.1:8000/redoc"
  echo ""
  info "按 Ctrl+C 停止服务"
  echo "============================================"
  uvicorn main:app --reload 2>&1
}

main() {
  echo "============================================"
  echo "  FastAPI 高性能 API 实战 一键脚本"
  echo "  适用于 macOS / Linux / WSL"
  echo "  默认接入：云间 API 中转站"
  echo "============================================"
  echo ""

  if ! check_python3; then exit 1; fi

  local NET
  NET=$(detect_network)

  if ! setup_venv; then exit 1; fi
  if ! install_fastapi "$NET"; then
    error "安装失败，脚本终止。请按上方提示手动处理。"
    exit 1
  fi

  generate_main_py
  configure_api

  echo ""
  echo "============================================"
  info "安装完成！接下来启动服务..."
  echo "  cd ~/fastapi-app && source .venv/bin/activate && uvicorn main:app --reload"
  echo "  然后访问 http://127.0.0.1:8000/docs 查看自动文档"
  echo ""
  echo "  想省 GPU/精力：云端 API 中转站（https://cloudzone-api.cyou/，90+ 模型按量计费）"
  echo "============================================"

  read -r -p "是否立即启动服务？[Y/N]: " start_now
  if [ "${start_now:-Y}" = "Y" ] || [ "${start_now:-Y}" = "y" ]; then
    run_service
  fi
}

main "$@"
