#!/usr/bin/env bash
set -u
# ============================================================
#  Flask Web 应用开发实战 一键脚本（macOS / Linux / WSL）
#  公开源码，欢迎审查 —— 不放心可先复制给 AI 判断
#  本教程不涉及 API Key，无需云间中转站配置
# ============================================================

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 环境..."
  local found=""
  for p in python3 python; do
    if command -v "$p" >/dev/null 2>&1 && "$p" --version 2>&1 | grep -qE "Python 3\.[0-9]+"; then
      found="$p"; break
    fi
  done
  if [ -n "$found" ]; then
    info "找到 $found：$($found --version 2>&1)"
    return 0
  fi
  error "未找到 Python 3。请先安装："
  echo "  · Ubuntu/Debian：sudo apt update && sudo apt install -y python3 python3-venv"
  echo "  · CentOS/RHEL：sudo yum install -y python3"
  echo "  · macOS：brew install python3"
  echo "  · 官网：https://www.python.org/downloads/"
  return 1
}

setup_project() {
  local net="$1"
  step "创建项目目录和虚拟环境..."
  mkdir -p flask-app && cd flask-app || return 1

  # 清理旧的虚拟环境（避免残留冲突）
  if [ -d ".venv" ]; then
    warn "发现已有的 .venv，删除后重新创建..."
    rm -rf .venv
  fi

  ${PY} -m venv .venv || { error "创建虚拟环境失败"; return 1; }

  # 激活虚拟环境
  # shellcheck disable=SC1091
  source .venv/bin/activate || { error "激活虚拟环境失败"; return 1; }

  info "虚拟环境已创建并激活"

  # ---- 升级 pip（防止旧版本导致下载失败）----
  step "升级 pip 包管理器..."
  if ! pip install --upgrade pip >/dev/null 2>&1; then
    warn "pip 升级失败，尝试用备用源..."
    pip install --upgrade pip -i "https://mirrors.aliyun.com/pypi/simple/" >/dev/null 2>&1 || \
      warn "pip 升级仍有问题，尝试继续安装依赖"
  fi
  info "pip 已就绪"

  # ---- 安装 Flask（清华镜像优先 → 阿里回退 → 官方源）----
  step "安装 Flask 及其依赖..."
  if pip install flask --timeout 120 -i "https://pypi.tuna.tsinghua.edu.cn/simple" >/dev/null 2>&1; then
    info "Flask 安装成功（清华镜像）"
  elif pip install flask --timeout 120 -i "https://mirrors.aliyun.com/pypi/simple" >/dev/null 2>&1; then
    info "Flask 安装成功（阿里镜像）"
  elif pip install flask --timeout 120 >/dev/null 2>&1; then
    info "Flask 安装成功（官方源）"
  else
    error "所有 PyPI 源均失败。请手动执行以下命令排查："
    echo "  pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple"
    return 1
  fi

  FLASK_VER=$(python3 -c "import flask; print(flask.__version__)")
  info "Flask 版本：$FLASK_VER"
}

generate_app() {
  step "生成 Flask 示例应用（留言簿）..."

  # 创建 templates 目录（Jinja2 模板必须放这里）
  mkdir -p templates

  # 写入主应用文件 app.py
  cat > app.py <<'APPEOF'
"""
Flask 留言簿示例 — 涵盖路由、视图、URL 参数、
Jinja2 模板渲染、表单 POST 请求、SQLite 存储。
"""
import sqlite3
import os
from flask import Flask, render_template, request, redirect, url_for, flash

app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY", "dev-change-in-production")

DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "messages.db")


def get_db():
    """获取数据库连接（每次请求新连接）"""
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row  # 让结果可以用列名访问
    return conn


def init_db():
    """初始化数据库表（首次运行时自动创建）"""
    conn = get_db()
    conn.execute("""
        CREATE TABLE IF NOT EXISTS messages (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            content TEXT NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    """)
    conn.commit()
    conn.close()


# --------------- 首页：列出所有留言 ---------------
@app.route("/")
def index():
    """GET / — 读取全部留言，交给首页模板渲染"""
    conn = get_db()
    rows = conn.execute("SELECT * FROM messages ORDER BY created_at DESC LIMIT 20").fetchall()
    conn.close()
    # rows 是 Row 对象列表，转为 dict 传给模板
    messages = [dict(r) for r in rows]
    return render_template("index.html", title="留言板", messages=messages)


# --------------- 提交留言（只接受 POST）--------------
@app.route("/add", methods=["POST"])
def add_message():
    """POST /add — 从表单读取 name+content，存入 SQLite"""
    name = request.form.get("name", "").strip()[:30]     # 最多 30 个字符
    content = request.form.get("content", "").strip()[:200]  # 最多 200 个字符

    if not name or not content:
        flash("昵称和内容都不能为空！", "error")
        return redirect(url_for("index"))

    conn = get_db()
    conn.execute("INSERT INTO messages (name, content) VALUES (?, ?)", (name, content))
    conn.commit()
    conn.close()
    flash("留言发布成功！")
    return redirect(url_for("index"))


# --------------- 按 ID 查看单条留言 --------------------
@app.route("/message/<int:message_id>")
def message_detail(message_id):
    """GET /message/1 — URL 参数查询单条留言"""
    conn = get_db()
    row = conn.execute("SELECT * FROM messages WHERE id = ?", (message_id,)).fetchone()
    conn.close()
    if row is None:
        flash("该留言不存在或已被删除。")
        return redirect(url_for("index"))
    return render_template(
        "index.html",
        title=f"留言 #{message_id}",
        messages=[dict(row)],       # 复用同一模板，只展示一条
        single_mode=True            # 传给模板做样式微调
    )


# --------------- 启动入口 --------------------------------
if __name__ == "__main__":
    init_db()                            # 建表
    app.run(host="0.0.0.0", port=5000, debug=True)
APPEOF

  # 写入 Jinja2 模板 templates/index.html
  cat > templates/index.html <<'HTMLEOF'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, "Microsoft YaHei", sans-serif; background: #f0f2f5; color: #333; line-height: 1.6; padding: 1rem; }
    .container { max-width: 720px; margin: 0 auto; }
    h1 { text-align: center; margin-bottom: 1rem; color: #1a1a2e; }
    form { background: #fff; border-radius: 8px; padding: 1.5rem; margin-bottom: 1.5rem; box-shadow: 0 2px 4px rgba(0,0,0,.08); }
    label { display: block; margin-top: .8rem; font-weight: 600; }
    input[type=text], textarea { width: 100%; padding: .5rem; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; margin-top: .3rem; }
    textarea { height: 80px; resize: vertical; }
    button { margin-top: 1rem; padding: .6rem 1.5rem; background: #4361ee; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 15px; }
    button:hover { background: #3a56d4; }
    .flash-error { background: #ffe0e0; color: #c0392b; padding: .6rem; border-radius: 4px; margin-bottom: 1rem; }
    .flash-ok { background: #e0ffe0; color: #27ae60; padding: .6rem; border-radius: 4px; margin-bottom: 1rem; }
    .msg-card { background: #fff; border-radius: 8px; padding: 1rem 1.2rem; margin-bottom: .8rem; box-shadow: 0 1px 3px rgba(0,0,0,.06); }
    .msg-card a { color: #4361ee; text-decoration: none; font-weight: 600; }
    .msg-card a:hover { text-decoration: underline; }
    .meta { font-size: 12px; color: #999; margin-top: .3rem; }
  </style>
</head>
<body>
<div class="container">
  <h1>{{ title }}</h1>

  {% with messages = get_flashed_messages(with_categories=true) %}
    {% for category, msg in messages %}
      <div class="{{ 'flash-error' if category == 'error' else 'flash-ok' }}">{{ msg }}</div>
    {% endfor %}
  {% endwith %}

  <!-- 留言表单：method="POST" 把数据发到 /add -->
  <form method="POST" action="{{ url_for('add_message') }}">
    <label for="name">你的昵称：</label>
    <input type="text" id="name" name="name" placeholder="例如：小明" required>

    <label for="content">留言内容：</label>
    <textarea id="content" name="content" placeholder="说点什么吧……" required></textarea>

    <button type="submit">发布留言</button>
  </form>

  <!-- 留言列表（单篇模式下只显示一条） -->
  {% if messages %}
    {% for m in messages %}
      <div class="msg-card">
        <a href="{{ url_for('message_detail', message_id=m.id) }}">{{ m.name }}：</a>{{ m.content }}
        <div class="meta">{{ m.created_at }}</div>
      </div>
    {% endfor %}
  {% endif %}
</div>
</body>
</html>
HTMLEOF

  info "已生成 app.py 与 templates/index.html"
}

verify_site() {
  step "启动服务并在后台验证页面可达性..."
  # 启动 Flask 到后台
  python app.py &
  APP_PID=$!

  # 等服务器启动（最多等待 10 秒）
  local waited=0
  while [ $waited -lt 10 ]; do
    if curl -fsI --max-time 3 "http://localhost:5000/" >/dev/null 2>&1; then
      break
    fi
    sleep 1
    waited=$((waited + 1))
  done

  if [ $waited -ge 10 ]; then
    kill $APP_PID 2>/dev/null
    error "Flask 服务未能启动，请检查上方报错信息"
    return 1
  fi

  # 验证首页 200
  local STATUS
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "http://localhost:5000/")
  if [ "$STATUS" = "200" ]; then
    info "首页 http://localhost:5000/ 返回 $STATUS —— 一切正常！"
  else
    error "首页返回 $STATUS（期望 200），请检查上方 Flask 日志"
    kill $APP_PID 2>/dev/null
    return 1
  fi

  # 提交一条测试留言
  STEP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 \
    -X POST "http://localhost:5000/add" \
    -d "name=测试用户&content=这是一条自动化测试留言" 2>/dev/null)
  if [ "$STEP_STATUS" = "302" ] || [ "$STEP_STATUS" = "200" ]; then
    info "POST /add 返回 $STEP_STATUS —— 表单提交流程正常"
  else
    warn "POST /add 返回 $STEP_STATUS（期望 302/200），可能仍需手动验证"
  fi

  # 停止后台进程
  kill $APP_PID 2>/dev/null
  wait $APP_PID 2>/dev/null
}

main() {
  echo "============================================"
  echo "  Flask Web 应用开发实战 一键脚本"
  echo "  适用于 macOS / Linux / WSL"
  echo "  功能：环境检查 → 安装 Flask → 生成留言簿 → 自动验证"
  echo "============================================"
  echo ""

  if ! check_python3; then exit 1; fi
  # 记住找到的 python3 路径，供后续步骤使用
  for p in python3 python; do
    if command -v "$p" >/dev/null 2>&1 && "$p" --version 2>&1 | grep -qE "Python 3\.[0-9]+"; then
      PY="$p"; break
    fi
  done

  local NET
  NET=$(detect_network)

  setup_project "$NET"
  generate_app
  verify_site

  echo ""
  echo "============================================"
  info "全部完成！"
  echo "  进入项目目录：cd flask-app"
  echo "  激活虚拟环境：source .venv/bin/activate"
  echo "  启动服务：    python app.py"
  echo "  访问首页：    浏览器打开 http://localhost:5000/"
  echo "  退出环境：    deactivate"
  echo ""
  echo "  下一步阅读：文章正文详细讲解每一步的原理与用法"
  echo "============================================"
}

main "$@"
