#!/usr/bin/env bash
# Verify 1Panel + Docker install wizard readiness (run on the VPS as root).
# See: deploy/README-1panel.md
set -euo pipefail

NEXUS_ROOT="${NEXUS_ROOT:-/opt/nexus}"
ENV_PROD="${NEXUS_ROOT}/docker/.env.prod"
COMPOSE_FILE="${NEXUS_ROOT}/docker/docker-compose.prod.yml"
COMPOSE_1PANEL="${NEXUS_ROOT}/docker/docker-compose.1panel.yml"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

pass() { echo -e "${GREEN}[PASS]${NC} $*"; }
fail() { echo -e "${RED}[FAIL]${NC} $*"; FAILURES=$((FAILURES + 1)); }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; WARNS=$((WARNS + 1)); }
info() { echo -e "       $*"; }

FAILURES=0
WARNS=0
INSTALL_WIZARD_ARCHIVED=false
PUBLISH_PORT=8600

require_root() {
    if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
        fail "请用 root 运行（1Panel 终端默认 root）"
        exit 1
    fi
}

resolve_nexus_container() {
    NEXUS_CONTAINER="$(docker ps --format '{{.Names}}' | grep -E 'nexus-prod-nexus|nexus-nexus-1' | head -1 || true)"
    if [[ -z "$NEXUS_CONTAINER" ]]; then
        fail "未找到运行中的 Nexus 容器"
        info "修复: cd $NEXUS_ROOT && nx update --no-cache"
        return 1
    fi
    pass "Nexus 容器: $NEXUS_CONTAINER"
}

check_repo() {
    if [[ ! -d "$NEXUS_ROOT/.git" ]]; then
        fail "仓库不存在: $NEXUS_ROOT"
        return 1
    fi
    local sha msg
    sha="$(git -C "$NEXUS_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
    msg="$(git -C "$NEXUS_ROOT" log -1 --oneline 2>/dev/null || true)"
    pass "Git: $msg"
    if git -C "$NEXUS_ROOT" merge-base --is-ancestor b25d079 HEAD 2>/dev/null; then
        pass "已包含 b25d079（1Panel 容器名 sync 修复）"
    else
        warn "早于 b25d079 — 步骤 3 可能仍预填 host.docker.internal"
        info "修复: cd $NEXUS_ROOT && nx update --no-cache"
    fi
    if git -C "$NEXUS_ROOT" merge-base --is-ancestor 3b2856f HEAD 2>/dev/null; then
        pass "已包含 3b2856f+（Redis :pass@ 自动解析，无 root）"
    else
        warn "早于 3b2856f — Redis 认证可能仍误用 root"
        info "修复: cd $NEXUS_ROOT && git pull && bash deploy/sync-install-wizard-to-container.sh"
    fi
}

check_env_prod() {
    if [[ ! -f "$ENV_PROD" ]]; then
        fail "缺少 $ENV_PROD"
        info "修复: bash $NEXUS_ROOT/deploy/install-nexus-fresh.sh --skip-clone"
        return 1
    fi
    pass "docker/.env.prod 存在"
    PUBLISH_PORT="$(grep -E '^NEXUS_PUBLISH_PORT=' "$ENV_PROD" 2>/dev/null | cut -d= -f2- | tr -d '\r" ' || true)"
    PUBLISH_PORT="${PUBLISH_PORT:-8600}"
    pass "NEXUS_PUBLISH_PORT=$PUBLISH_PORT"
    if grep -qE '^NEXUS_INSTALL_WIZARD_PENDING=1' "$ENV_PROD"; then
        pass "NEXUS_INSTALL_WIZARD_PENDING=1（安装模式）"
    else
        warn "NEXUS_INSTALL_WIZARD_PENDING≠1 — entrypoint 可能已写 /app/.env"
    fi
    local db redis
    db="$(grep -E '^NEXUS_1PANEL_DB_HOST=' "$ENV_PROD" 2>/dev/null | cut -d= -f2- || true)"
    redis="$(grep -E '^NEXUS_1PANEL_REDIS_HOST=' "$ENV_PROD" 2>/dev/null | cut -d= -f2- || true)"
    if [[ -n "$db" ]]; then
        pass "NEXUS_1PANEL_DB_HOST=$db"
    else
        fail "未设置 NEXUS_1PANEL_DB_HOST"
        info "修复: bash $NEXUS_ROOT/deploy/detect-1panel-services.sh && nx update"
    fi
    if [[ -n "$redis" ]]; then
        pass "NEXUS_1PANEL_REDIS_HOST=$redis"
        local rurl
        rurl="$(grep -E '^NEXUS_REDIS_URL=' "$ENV_PROD" 2>/dev/null | cut -d= -f2- || true)"
        if [[ "$rurl" == *"$redis"* ]]; then
            pass "NEXUS_REDIS_URL 已指向 Redis 容器"
        else
            warn "NEXUS_REDIS_URL 未含 $redis — nx update 会同步"
        fi
    else
        fail "未设置 NEXUS_1PANEL_REDIS_HOST"
        info "修复: 在 1Panel 应用商店安装 Redis 后执行 nx update"
    fi
}

check_1panel_network() {
    if ! docker network inspect 1panel-network >/dev/null 2>&1; then
        fail "1panel-network 不存在"
        info "修复: 在 1Panel 应用商店安装 MySQL + Redis（会自动创建网络）"
        return 1
    fi
    pass "1panel-network 存在"
    if [[ -n "${NEXUS_CONTAINER:-}" ]]; then
        if docker inspect "$NEXUS_CONTAINER" --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' \
            | grep -q '1panel-network'; then
            pass "Nexus 已接入 1panel-network"
        else
            fail "Nexus 未接入 1panel-network"
            info "修复: cd $NEXUS_ROOT && nx update --no-cache"
        fi
    fi
    if [[ -x "$NEXUS_ROOT/deploy/detect-1panel-services.sh" ]]; then
        info "探测结果:"
        "$NEXUS_ROOT/deploy/detect-1panel-services.sh" | sed 's/^/         /' || true
    fi
}

probe_from_container() {
    [[ -n "${NEXUS_CONTAINER:-}" ]] || return 0
    local db redis
    db="$(grep -E '^NEXUS_1PANEL_DB_HOST=' "$ENV_PROD" 2>/dev/null | cut -d= -f2- || true)"
    redis="$(grep -E '^NEXUS_1PANEL_REDIS_HOST=' "$ENV_PROD" 2>/dev/null | cut -d= -f2- || true)"
    if [[ -n "$db" ]]; then
        if docker exec "$NEXUS_CONTAINER" python3 -c "
import socket
s=socket.socket(); s.settimeout(3); s.connect(('$db', 3306)); s.close()
" 2>/dev/null; then
            pass "容器内 TCP → MySQL $db:3306"
        else
            fail "容器内无法连接 MySQL $db:3306"
            info "检查 MySQL 容器是否运行、Nexus 是否在 1panel-network"
        fi
    fi
    if [[ -n "$redis" ]]; then
        if docker exec "$NEXUS_CONTAINER" python3 -c "
import socket
s=socket.socket(); s.settimeout(3); s.connect(('$redis', 6379)); s.close()
" 2>/dev/null; then
            pass "容器内 TCP → Redis $redis:6379"
        else
            fail "容器内无法连接 Redis $redis:6379"
        fi
    fi
}

check_app_env_redis_url() {
    [[ -n "${NEXUS_CONTAINER:-}" ]] || return 0
    if ! docker exec "$NEXUS_CONTAINER" test -f /app/.env 2>/dev/null; then
        return 0
    fi
    local rurl
    rurl="$(docker exec "$NEXUS_CONTAINER" grep -E '^NEXUS_REDIS_URL=' /app/.env 2>/dev/null | cut -d= -f2- | tr -d '"' || true)"
    if [[ -z "$rurl" ]]; then
        warn "/app/.env 无 NEXUS_REDIS_URL"
        return 0
    fi
    if [[ "$rurl" == *"://root:"* ]]; then
        fail "NEXUS_REDIS_URL 含 root 用户（1Panel Redis 无 root 账号）"
        info "修复: redis://:密码@1Panel-redis-xxxx:6379/0 — 见 deploy/test-1panel-redis.sh"
    elif [[ "$rurl" == *"1Panel-redis"* ]] || [[ "$rurl" == *"://:"* ]]; then
        pass "NEXUS_REDIS_URL 格式合理（容器名或 :pass@）"
    else
        warn "NEXUS_REDIS_URL 可能未指向 1Panel Redis: $rurl"
    fi
}

check_install_mode() {
    [[ -n "${NEXUS_CONTAINER:-}" ]] || return 0
    if docker exec "$NEXUS_CONTAINER" test -f /app/.env 2>/dev/null; then
        warn "/app/.env 已存在 — 安装向导可能已进入步骤 3+ 或误写 env"
        check_app_env_redis_url
        info "若需重来: 删卷 nexus-state 中 .env 并设 NEXUS_INSTALL_WIZARD_PENDING=1 后 nx update"
    else
        pass "/app/.env 不存在（安装模式 OK）"
    fi
    if docker exec "$NEXUS_CONTAINER" test -f /app/.install_locked 2>/dev/null \
        || docker exec "$NEXUS_CONTAINER" test -f /var/lib/nexus/.install_locked 2>/dev/null \
        || docker exec "$NEXUS_CONTAINER" test -f /app/web/app/install.html.bak 2>/dev/null; then
        pass "安装向导已锁定/已归档 — 应访问 /app/ 登录"
        INSTALL_WIZARD_ARCHIVED=true
    fi
    local hosts_json
    hosts_json="$(docker exec "$NEXUS_CONTAINER" cat /app/web/data/1panel-hosts.json 2>/dev/null || true)"
    if [[ -n "$hosts_json" ]]; then
        pass "1panel-hosts.json: $hosts_json"
    else
        warn "无 1panel-hosts.json（依赖容器环境变量，nx update 会写入）"
    fi
}

check_ops_cron() {
    if [[ "${INSTALL_WIZARD_ARCHIVED:-false}" != true ]]; then
        return 0
    fi
    if ! command -v crontab >/dev/null 2>&1; then
        warn "未安装 cron/crontab — Layer 3 宿主机巡检不可用"
        info "修复: sudo bash $NEXUS_ROOT/deploy/install_ops_cron.sh"
        return 0
    fi
    local cron
    cron="$(crontab -l 2>/dev/null || true)"
    if echo "$cron" | grep -q 'nexus-health-monitor\|deploy/health_monitor.sh'; then
        pass "Crontab 含 health_monitor"
    else
        warn "Crontab 未配置 health_monitor（Layer 3 巡检）"
        info "修复: sudo nx cron"
    fi
    if echo "$cron" | grep -q 'nexus-mysql-backup\|deploy/db_backup.sh'; then
        pass "Crontab 含 db_backup"
    else
        warn "Crontab 未配置 db_backup（每日 MySQL 备份）"
        info "修复: sudo nx cron"
    fi
}

check_mysql_backup() {
    if [[ "${INSTALL_WIZARD_ARCHIVED:-false}" != true ]]; then
        return 0
    fi
    local dump_sh="${NEXUS_ROOT}/deploy/mysql_dump_to_file.sh"
    if [[ -f "$dump_sh" ]]; then
        pass "mysql_dump_to_file.sh 存在"
    else
        warn "缺少 mysql_dump_to_file.sh — 升级前无法备份 MySQL"
        info "修复: cd $NEXUS_ROOT && git pull && nx update"
        return 0
    fi
    if [[ -d /var/backups/nexus ]] && ls /var/backups/nexus/nexus_*.sql.gz >/dev/null 2>&1; then
        local latest
        latest="$(ls -t /var/backups/nexus/nexus_*.sql.gz 2>/dev/null | head -1)"
        pass "已有 MySQL 备份: $(basename "$latest")"
    else
        warn "尚无 MySQL 备份文件（/var/backups/nexus）"
        info "可手动: sudo bash $NEXUS_ROOT/deploy/db_backup.sh"
    fi
}

check_http_local() {
    local health code
    health="$(curl -sf "http://127.0.0.1:${PUBLISH_PORT}/health" 2>/dev/null || true)"
    if [[ "$health" == "ok" ]]; then
        pass "/health → ok"
    else
        fail "/health 非 ok（当前: ${health:-无响应}）"
        info "修复: docker logs --tail=80 $NEXUS_CONTAINER"
        return 1
    fi
    code="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:${PUBLISH_PORT}/app/install.html" 2>/dev/null || echo 000)"
    if [[ "${INSTALL_WIZARD_ARCHIVED:-false}" == true ]]; then
        if [[ "$code" == "404" ]]; then
            pass "/app/install.html 已归档 → HTTP 404"
        else
            fail "/app/install.html 应已归档但 HTTP $code"
            info "修复: nx update（会执行 archive_install_wizard_in_container）"
        fi
        return 0
    fi
    if [[ "$code" == "200" ]]; then
        pass "/app/install.html → HTTP 200"
    else
        fail "/app/install.html → HTTP $code"
        info "修复: bash $NEXUS_ROOT/deploy/sync-install-wizard-to-container.sh"
    fi
}

check_install_api() {
    if [[ "${INSTALL_WIZARD_ARCHIVED:-false}" == true ]]; then
        pass "安装 API 已关闭（向导已锁定，/api/install/* 返回 403 为预期）"
        return 0
    fi
    local status env_json
    status="$(curl -sf "http://127.0.0.1:${PUBLISH_PORT}/api/install/status" 2>/dev/null || true)"
    if [[ -n "$status" ]]; then
        pass "/api/install/status → $status"
        if echo "$status" | grep -q '"installed":true'; then
            warn "installed=true — 向导已完成，请访问 /app/ 登录"
        fi
    else
        fail "/api/install/status 无响应"
    fi
    env_json="$(curl -sf "http://127.0.0.1:${PUBLISH_PORT}/api/install/env-check" 2>/dev/null || true)"
    if [[ -z "$env_json" ]]; then
        fail "/api/install/env-check 无响应"
        return 1
    fi
    if echo "$env_json" | grep -q 'docker_defaults'; then
        local db_host
        db_host="$(echo "$env_json" | python3 -c "
import json,sys
d=json.load(sys.stdin)
print((d.get('docker_defaults') or {}).get('db_host',''))
" 2>/dev/null || true)"
        if [[ -n "$db_host" && "$db_host" != "host.docker.internal" ]]; then
            pass "步骤 3 预填 db_host=$db_host"
        elif [[ "$db_host" == "host.docker.internal" ]]; then
            fail "步骤 3 仍预填 host.docker.internal"
            info "修复: nx update --no-cache（需 b25d079+）"
        fi
    else
        warn "env-check 无 docker_defaults（非 Docker 模式？）"
    fi
    if echo "$env_json" | grep -q '1Panel-mysql'; then
        pass "env-check MySQL 探测含 1Panel 容器名"
    elif echo "$env_json" | grep -q 'host.docker.internal'; then
        warn "env-check MySQL 仍指向 host.docker.internal"
    fi
}

check_container_image_features() {
    [[ -n "${NEXUS_CONTAINER:-}" ]] || return 0
    local host_sha py_ok html_file html_ok host_root_ok
    host_sha="$(git -C "$NEXUS_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
    pass "宿主机 Git: $host_sha"

    if docker exec "$NEXUS_CONTAINER" grep -q '_host_deploy_root' /app/server/api/install.py 2>/dev/null; then
        pass "容器 install.py 含 host_deploy_root（round6+）"
        py_ok=1
    else
        warn "容器 install.py 较旧 — 需 nx update 重建镜像"
    fi

    html_file="/app/web/app/install.html"
    if docker exec "$NEXUS_CONTAINER" test -f /app/web/app/install.html.bak 2>/dev/null; then
        html_file="/app/web/app/install.html.bak"
    fi
    if docker exec "$NEXUS_CONTAINER" grep -q 'install_ops_cron' "$html_file" 2>/dev/null; then
        pass "容器 install.html 含 Layer 3 cron 指引（round7+）"
        html_ok=1
    else
        warn "容器 install.html 较旧 — 需 nx update 重建镜像"
    fi

    host_root_ok="$(docker exec "$NEXUS_CONTAINER" printenv NEXUS_HOST_ROOT 2>/dev/null || true)"
    if [[ -n "$host_root_ok" ]]; then
        pass "NEXUS_HOST_ROOT=$host_root_ok"
    else
        warn "容器未注入 NEXUS_HOST_ROOT — nx update 重建后可修复"
    fi

    if [[ -n "${py_ok:-}" && -n "${html_ok:-}" ]]; then
        info "镜像与宿主机代码特性对齐（重建后验收）"
    else
        info "修复: cd $NEXUS_ROOT && sudo nx update"
    fi
}

check_openresty_hint() {
    local domain code
    domain="$(grep -E '^NEXUS_API_BASE_URL=' "$ENV_PROD" 2>/dev/null | sed 's|.*https\?://||;s|/.*||' || echo api.synaglobal.vip)"
    code="$(curl -sk -o /dev/null -w '%{http_code}' --connect-timeout 5 "https://${domain}/health" 2>/dev/null || echo 000)"
    if [[ "$code" == "200" ]] && curl -sk "https://${domain}/health" 2>/dev/null | grep -q '^ok$'; then
        pass "HTTPS https://${domain}/health → ok"
    else
        warn "HTTPS https://${domain}/health → HTTP $code（外网可能未配 OpenResty 反代）"
        info "1Panel → 网站 → 反代 http://127.0.0.1:8600"
        info "参考: $NEXUS_ROOT/deploy/1panel/openresty-nexus.conf.example"
    fi
}

print_next_steps() {
    local domain
    domain="$(grep -E '^NEXUS_API_BASE_URL=' "$ENV_PROD" 2>/dev/null | sed 's|.*https\?://||;s|/.*||' || echo '你的域名')"
    echo ""
    if [[ "${INSTALL_WIZARD_ARCHIVED:-false}" == true ]]; then
        echo "=========================================="
        echo " 已安装 — 日常运维"
        echo "=========================================="
        echo "  登录: https://${domain}/app/"
        echo "  更新: cd $NEXUS_ROOT && nx update"
        echo "  巡检 cron: sudo nx cron"
        echo "  手动备份: sudo bash $NEXUS_ROOT/deploy/db_backup.sh"
        echo "  验收: bash $NEXUS_ROOT/deploy/verify-1panel-install-wizard.sh"
        echo ""
        return 0
    fi
    echo "=========================================="
    echo " 安装向导后续步骤"
    echo "=========================================="
    echo "1. 1Panel 数据库 → 建库 nexus、用户 nexus（仅授权 nexus 库）"
    echo "2. 浏览器打开: https://${domain}/app/install.html"
    echo "3. 步骤 2：MySQL/Redis TCP 应显示 ✓（容器名:端口）"
    echo "4. 步骤 3：确认 db_host/redis_host 为 1Panel-mysql/redis-xxxx，填 MySQL 密码"
    echo "5. 步骤 4：连接检测全绿 → 创建 admin"
    echo "6. 步骤 5：锁定安装"
    echo ""
    if [[ "$FAILURES" -gt 0 ]]; then
        echo "先修复上方 [FAIL]，再执行:"
        echo "  cd $NEXUS_ROOT && nx update --no-cache"
    fi
}

main() {
    require_root
    echo "Nexus 1Panel 安装向导验收 — $(date -Iseconds)"
    echo "NEXUS_ROOT=$NEXUS_ROOT"
    echo ""

    check_repo || true
    check_env_prod || true
    resolve_nexus_container || true
    check_1panel_network || true
    probe_from_container || true
    check_install_mode || true
    check_http_local || true
    check_install_api || true
    check_ops_cron || true
    check_mysql_backup || true
    check_container_image_features || true
    check_openresty_hint || true
    print_next_steps

    if [[ "$FAILURES" -gt 0 ]]; then
        echo ""
        fail "合计 $FAILURES 项未通过"
        exit 1
    fi
    echo ""
    if [[ "${INSTALL_WIZARD_ARCHIVED:-false}" == true ]]; then
        pass "验收通过 — 安装已完成，请访问 /app/ 登录"
        if [[ "$WARNS" -gt 0 ]]; then
            warn "有 ${WARNS} 项 [WARN]（cron/备份等建议项，不阻断登录）"
        fi
    else
        pass "验收通过 — 可打开安装向导完成步骤 1–5"
    fi
}

main "$@"
