#!/usr/bin/env bash
# Phase 0/1 服务器一次性初始化：Docker / Compose / Caddy / 防火墙 / 网络
#
# 用法：sudo bash setup-test-server.sh
#
# 模式自动判定：
#   - **独立模式**（dev 沙箱 43.166.182.155，:80/:443 空闲）：Caddy 绑 0.0.0.0:80/443，自管 cert
#   - **共机模式**（Phase 1 三环境，与 FF AI Workspace 主站 nginx 共机）：Caddy 绑 127.0.0.1:8080，
#     nginx 终止 TLS + 反代 *.apps.* → Caddy。详见 docs/modules/internal-app-platform/12-nginx-caddy-coexist.md
#
# 幂等：重复运行只补缺失项。

set -euo pipefail

log() { printf '\n\033[1;36m[setup]\033[0m %s\n' "$*"; }
ok()  { printf '  \033[1;32m✓\033[0m %s\n' "$*"; }

# 确认 root
if [[ $EUID -ne 0 ]]; then
  echo "需要 sudo 运行：sudo bash $0" >&2
  exit 1
fi

REAL_USER="${SUDO_USER:-lijian}"

# ---------- 1. APT 基础工具 ----------
log "1/6 安装基础工具"
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq ca-certificates curl gnupg lsb-release ufw jq git >/dev/null
ok "curl/gnupg/ufw/jq/git 就绪"

# ---------- 2. Docker CE + compose plugin ----------
if ! command -v docker >/dev/null; then
  log "2/6 安装 Docker CE"
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  chmod a+r /etc/apt/keyrings/docker.gpg
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
    > /etc/apt/sources.list.d/docker.list
  apt-get update -qq
  apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin >/dev/null
  systemctl enable --now docker
  usermod -aG docker "$REAL_USER"
  ok "Docker $(docker --version | awk '{print $3}' | tr -d ,) 已装，$REAL_USER 已加 docker 组"
else
  log "2/6 Docker 已装：$(docker --version)"
fi

# ---------- 3. ffoa-network ----------
log "3/6 docker 网络 ffoa-network"
docker network inspect ffoa-network >/dev/null 2>&1 || docker network create ffoa-network >/dev/null
ok "ffoa-network OK"

# ---------- 4. Caddy（用容器跑，免污染系统）----------
# 共机检测：:80 被占（疑似 nginx）→ 走方案 B（Caddy 绑 127.0.0.1:8080，nginx 终止 TLS）
COEXIST_MODE=0
if ss -tlnp 2>/dev/null | grep -qE '\s(0\.0\.0\.0|\[::\]|\*):80\s' && \
   ! docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^ffoa-caddy$'; then
  COEXIST_MODE=1
  log "4/6 Caddy 反代容器（共机模式：Caddy 绑 127.0.0.1:8080，由前置 nginx 终止 TLS）"
else
  log "4/6 Caddy 反代容器（独立模式：Caddy 绑 :80/:443/:2019）"
fi
install -d -o "$REAL_USER" -g "$REAL_USER" /srv/caddy /srv/caddy/sites /srv/caddy/data /srv/caddy/config
chmod 0755 /srv/caddy /srv/caddy/sites
if [[ ! -f /srv/caddy/Caddyfile ]]; then
  cat >/srv/caddy/Caddyfile <<'CADDY'
# Phase 0 默认 Caddyfile —— internal-app-platform deploy 脚本会往
# /srv/caddy/sites/ 写 per-app 反代片段，admin API reload 后生效。
{
    admin 0.0.0.0:2019
}

# 健康检查（裸 IP 命中此 site，便于运维 ping）
:80 {
    @healthz path /healthz
    respond @healthz "ok" 200
}

# 每个 app 一个文件，按 employee-app.caddy 命名
import /etc/caddy/sites/*.caddy
CADDY
  chown "$REAL_USER:$REAL_USER" /srv/caddy/Caddyfile
fi
docker rm -f ffoa-caddy >/dev/null 2>&1 || true
# --add-host host.docker.internal:host-gateway 让 Caddy 容器能反代到宿主上跑的
# backend (pm2 :3000) 和 frontend (pm2 :4000)。详见 .learnings/2026-05-14-caddy-host-gateway.md
if [[ $COEXIST_MODE -eq 1 ]]; then
  PORTS_ARGS=(-p 127.0.0.1:8080:80 -p 127.0.0.1:2019:2019)
else
  PORTS_ARGS=(-p 80:80 -p 443:443 -p 2019:2019)
fi
docker run -d --name ffoa-caddy --restart unless-stopped \
  --network ffoa-network \
  --add-host host.docker.internal:host-gateway \
  "${PORTS_ARGS[@]}" \
  -v /srv/caddy:/etc/caddy \
  -v /srv/caddy/data:/data \
  -v /srv/caddy/config:/config \
  caddy:2-alpine >/dev/null
if [[ $COEXIST_MODE -eq 1 ]]; then
  ok "Caddy 已起（共机模式）：内部 :8080 → 127.0.0.1:8080，admin :2019 → 127.0.0.1:2019，sites: /srv/caddy/sites/"
else
  ok "Caddy 已起（独立模式）：:80/:443/:2019 公网暴露，sites: /srv/caddy/sites/"
fi

# ---------- 5. UFW 防火墙 ----------
log "5/6 防火墙规则（22/80/443 公网；9000/9001/2019/8080 仅本机）"
# 两个模式都需要开 :80/:443：
#   独立模式：Caddy 直接监听 :80/:443
#   共机模式：宿主 nginx 监听 :80/:443（关掉就把整台机器主站打挂；ERR-20260516-003）
ufw allow 22/tcp >/dev/null
ufw allow 80/tcp >/dev/null
ufw allow 443/tcp >/dev/null
# 共机模式：Caddy 走 127.0.0.1:8080，禁止公网访问 :8080
if [[ $COEXIST_MODE -eq 1 ]]; then
  ufw deny 8080/tcp >/dev/null
fi
# MinIO + Caddy admin 不暴露公网（两模式一致）
ufw deny 9000/tcp >/dev/null
ufw deny 9001/tcp >/dev/null
ufw deny 2019/tcp >/dev/null
echo "y" | ufw enable >/dev/null 2>&1 || true
ok "ufw 已开"

# ---------- 6. 应用部署根目录 ----------
log "6/6 internal-app-platform 部署根目录"
install -d -o "$REAL_USER" -g "$REAL_USER" /srv/internal-apps
install -d -o "$REAL_USER" -g "$REAL_USER" /srv/internal-apps/repos
install -d -o "$REAL_USER" -g "$REAL_USER" /srv/internal-apps/data
ok "/srv/internal-apps/{repos,data} 就绪（owner=$REAL_USER）"

# ---------- 7. 30 天保留期 sweep cron（Phase 1）----------
log "7/8 sweep-expired-apps systemd timer（每天 03:00）"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [[ -f "$SCRIPT_DIR/sweep-expired-apps.sh" ]]; then
  install -m 0755 "$SCRIPT_DIR/sweep-expired-apps.sh" /usr/local/bin/ffoa-sweep-expired-apps
  install -m 0644 "$SCRIPT_DIR/ffoa-sweep-expired-apps.service" /etc/systemd/system/
  install -m 0644 "$SCRIPT_DIR/ffoa-sweep-expired-apps.timer" /etc/systemd/system/
  # 日志目录
  install -d -o "$REAL_USER" -g "$REAL_USER" -m 0750 /var/log
  touch /var/log/ffoa-sweep-expired-apps.jsonl
  chown "$REAL_USER:$REAL_USER" /var/log/ffoa-sweep-expired-apps.jsonl
  systemctl daemon-reload
  systemctl enable --now ffoa-sweep-expired-apps.timer >/dev/null 2>&1
  ok "ffoa-sweep-expired-apps.timer enabled (next: $(systemctl show ffoa-sweep-expired-apps.timer --property=NextElapseUSecRealtime --value 2>/dev/null || echo n/a))"
else
  log "  ⚠️  跳过：sweep-expired-apps.sh 不在 scripts/internal-app-platform/ 下"
fi

# ---------- 8. deploy 入口 symlink（防 stale binary）----------
# backend container-host.service.ts 调 /usr/local/bin/ffoa-deploy 执行部署。历史上这是
# plain cp，git 更新 deploy-container.sh 也不会同步 → 跨进程契约 + stale binary 双重坑。
# 改 symlink：仓库脚本即唯一源，git pull 后立刻生效。详见
# .learnings/2026-05-19-ffoa-deploy-binary-stale-symlink-fix.md
log "8/8 ffoa-deploy symlink → 仓库脚本"
if [[ -f "$SCRIPT_DIR/deploy-container.sh" ]]; then
  ln -sfn "$SCRIPT_DIR/deploy-container.sh" /usr/local/bin/ffoa-deploy
  ok "/usr/local/bin/ffoa-deploy → $SCRIPT_DIR/deploy-container.sh"
else
  log "  ⚠️  跳过：deploy-container.sh 不在 $SCRIPT_DIR/"
fi

log "完成"
cat <<EOF

下一步（以 $REAL_USER 身份）：
  newgrp docker          # 让 docker 组立即生效
  docker run hello-world # 验证
  # 然后再起 MinIO：
  cd /srv/internal-apps && \\
    curl -fL http://43.130.59.228/FFAIWorkspace/workspace/raw/branch/feature/internal-app-platform/scripts/internal-app-platform/docker-compose.minio.yml -o minio.yml
  # 或者从本机 scp 上来。

EOF
