#!/usr/bin/env bash
set -u
# ============================================================
#  LangChain RAG 知识库问答 一键脚本（macOS / Linux / WSL）
#  公开源码，欢迎审查 —— 不放心可先复制给 AI 判断
#  默认配置：云间 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"; }

CLOUDZONE_URL="https://cloudzone-api.cyou"
CLOUDZONE_API_BASE="https://cloudzone-api.cyou/v1"

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_python() {
  step "检查 Python 3..."
  if command -v python3 >/dev/null 2>&1 && python3 --version >/dev/null 2>&1; then
    PY="python3"
    info "找到 python3：$(python3 --version 2>&1)"
    return 0
  fi
  error "未找到 python3。请先安装：https://www.python.org/downloads/ （Windows 建议使用 WSL 后执行本脚本）"
  return 1
}

setup_env() {
  local net="$1"
  step "创建虚拟环境并安装 LangChain 依赖（约 2-3 分钟）..."
  mkdir -p rag-demo && cd rag-demo || return 1
  python3 -m venv .venv 2>/dev/null || { error "创建虚拟环境失败，手动执行：python3 -m venv .venv"; return 1; }
  # shellcheck disable=SC1091
  source .venv/bin/activate || { warn "激活虚拟环境失败，继续使用系统环境"; }

  step "安装依赖包..."
  local pypi="https://pypi.org/simple"
  if [ "$net" = "domestic" ]; then
    pypi="https://pypi.tuna.tsinghua.edu.cn/simple"
  fi

  if pip install "langchain[openai]" langchain-text-splitters requests numpy -i "$pypi" --timeout 90 >/dev/null 2>&1; then
    info "依赖安装成功"
    return 0
  fi
  warn "主源失败，回退备用镜像（阿里云 PyPI）..."
  if pip install "langchain[openai]" langchain-text-splitters requests numpy -i "https://mirrors.aliyun.com/pypi/simple" --timeout 90 >/dev/null 2>&1; then
    info "备用镜像安装成功"
    return 0
  fi
  error "依赖安装失败。请手动执行：pip install \"langchain[openai]\" langchain-text-splitters requests numpy -i https://pypi.tuna.tsinghua.edu.cn/simple"
  return 1
}

configure_api() {
  step "配置 API Key..."
  echo ""
  echo "RAG 的"回答"环节需要调用大模型 API，必须有一把 OpenAI 兼容的 Key。"
  echo "默认配置云间 API 中转站（OpenAI 兼容格式，一把 Key 调 Claude/GPT/DeepSeek/GLM）："
  echo "  · 国内直连免翻墙，按 token 精确计费，最低官方 0.05 倍起"
  echo ""
  echo "是否现在跳转注册并获取 API Key？"
  echo "  Y - 立即跳转至 ${CLOUDZONE_URL}"
  echo "  N - 我已有 Key（任一 OpenAI 兼容服务），自行输入"
  read -r -p "请选择 [Y/N]: " choice

  local API_KEY=""
  local BASE_URL="$CLOUDZONE_API_BASE"
  if [ "${choice:-N}" = "Y" ] || [ "${choice:-N}" = "y" ]; then
    info "正在打开浏览器..."
    if command -v xdg-open >/dev/null 2>&1; then
      xdg-open "$CLOUDZONE_URL" >/dev/null 2>&1
    elif command -v open >/dev/null 2>&1; then
      open "$CLOUDZONE_URL" >/dev/null 2>&1
    else
      warn "无法自动打开浏览器，请手动访问：$CLOUDZONE_URL"
    fi
    echo "注册后在控制台复制 Key（以 sk- 开头）。"
    read -r -p "粘贴你的 API Key: " API_KEY
    read -r -p "中转地址(直接回车用默认 ${CLOUDZONE_API_BASE}): " input_base
    [ -n "${input_base:-}" ] && BASE_URL="$input_base"
  else
    read -r -s -p "请输入你的 API Key (sk-...): " API_KEY
    echo
    echo "服务地址：OpenAI 官方可不填（默认 api.openai.com）；第三方兼容服务请填写其地址。"
    read -r -p "API 地址(直接回车用默认 ${CLOUDZONE_API_BASE}): " input_base
    [ -n "${input_base:-}" ] && BASE_URL="$input_base"
  fi

  if [ -z "${API_KEY:-}" ]; then
    error "未输入 API Key，跳过配置。可稍后手动设置环境变量后重跑。"
    return 1
  fi

  local SHELL_RC=""
  case "$SHELL" in
    */zsh)  SHELL_RC="$HOME/.zshrc" ;;
    */bash) SHELL_RC="$HOME/.bashrc" ;;
    *)      SHELL_RC="$HOME/.profile" ;;
  esac

  info "写入环境变量到 $SHELL_RC（仅 OPENAI_API_KEY 与 OPENAI_BASE_URL 两个变量，原值备份 .bak）"
  if [ -f "$SHELL_RC" ]; then
    sed -i.bak '/OPENAI_API_KEY/d; /OPENAI_BASE_URL/d' "$SHELL_RC"
  fi
  {
    echo ""
    echo "# LangChain RAG - 由一键脚本写入"
    echo "export OPENAI_API_KEY=\"$API_KEY\""
    echo "export OPENAI_BASE_URL=\"$BASE_URL\""
  } >> "$SHELL_RC"

  export OPENAI_API_KEY="$API_KEY"
  export OPENAI_BASE_URL="$BASE_URL"

  info "配置完成！"
  echo "  API Key : ${API_KEY:0:10}********"
  echo "  Base URL: $BASE_URL"
  echo ""
  warn "新开终端窗口后永久生效，或立即执行：source $SHELL_RC"
}

write_files() {
  step "生成示例资料与 Demo 代码 ..."
  cat > 资料.txt <<'TXTEOF'
【CleanResolver 员工手册·节选】
1. 考勤：上班时间 9:00-18:00，弹性迟到 15 分钟内不扣款。
2. 请假：事假需提前 1 天在 OA 系统提交申请；病假可当天电话联系直属主管报备，后补材料。
3. 年假：入职满一年享 5 天年假，每年递增 1 天，上限 15 天；年假需提前 3 天申请。
4. 加班：工作日加班按 1.5 倍工资计算，节假日按 3 倍；加班需要提前提交加班审批单。
5. 办公设备：新员工入职当天领取笔记本与显示器；设备损坏走 IT 工单报修。
6. 报销：差旅报销需在行程结束后 7 个工作日内提交，发票抬头为"CleanResolver 科技有限公司"。
TXTEOF

  cat > rag_demo.py <<'PYEOF'
import os
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate

print("===== RAG 知识库问答 Demo =====")

# 1. 加载本地资料
docs = []
with open("资料.txt", encoding="utf-8") as f:
    docs.append(Document(page_content=f.read(), metadata={"source": "资料.txt"}))

# 2. 切分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)
print(f"[1/5] 加载并切分完成：{len(all_splits)} 块")

# 3. 向量化入库
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vector_store = InMemoryVectorStore(embedding=embeddings)
vector_store.add_documents(documents=all_splits)
print("[2/5] 向量化入库完成")

# 4. 检索
question = input("[3/5] 请输入你的问题: ").strip()
retrieved_docs = vector_store.similarity_search(question, k=4)
context = "\n\n".join(doc.page_content for doc in retrieved_docs)
print(f"[4/5] 检索到 {len(retrieved_docs)} 段相关内容")

# 5. 回答
model = init_chat_model(model="gpt-5.5")
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个尽职的问答助手。只能依据下方提供的资料回答，资料里没有就说'资料中未找到'，不要编造。"),
    ("user", "资料：\n{context}\n\n问题：{question}"),
])
response = model.invoke(prompt.format_messages(context=context, question=question))

print("\n===== 回答 =====")
print(response.content)
PYEOF
  info "已生成 rag-demo/资料.txt 与 rag-demo/rag_demo.py"
}

main() {
  echo "============================================"
  echo "  LangChain RAG 知识库问答 一键脚本"
  echo "  适用于 macOS / Linux / WSL"
  echo "  默认接入：云间 API 中转站"
  echo "============================================"
  echo ""

  local NET
  NET=$(detect_network)

  if ! check_python; then
    error "缺少 Python 3，脚本终止。请先安装 Python 后重跑。"
    exit 1
  fi

  if ! setup_env "$NET"; then
    error "环境准备失败，脚本终止。请按上方提示手动处理。"
    exit 1
  fi

  configure_api || warn "Key 未配置，Demo 仍会生成，运行时需要先 export OPENAI_API_KEY"

  write_files

  echo ""
  echo "============================================"
  info "全部完成！运行你的知识库问答 Demo："
  echo "    cd rag-demo && source .venv/bin/activate && python rag_demo.py"
  echo "将 资料.txt 换成你自己的文档，改 rag_demo.py 里的 load 部分即可"
  echo "============================================"
}

main "$@"