#!/bin/bash

set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR"

VENV_DIR=".venv"
VENV_PYTHON="$VENV_DIR/bin/python"
LOG_DIR="logs"
API_PID_FILE="$LOG_DIR/api.pid"
FRONTEND_PID_FILE="$LOG_DIR/frontend.pid"
API_LOG_FILE="$LOG_DIR/api.log"
FRONTEND_LOG_FILE="$LOG_DIR/frontend.log"
DISPLAY_HOST="localhost"
SERVICE_HOST="6.86.80.8"

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

load_env() {
    load_env_file ".env"
    load_env_file ".env.development"

    API_HOST="${API_HOST:-0.0.0.0}"
    API_PORT="${API_PORT:-8000}"
    FRONTEND_PORT="${FRONTEND_PORT:-5173}"
    FRONTEND_MODE="${FRONTEND_MODE:-dev}"
}

load_env_file() {
    local env_file="$1"

    if [ -f "$env_file" ]; then
        while IFS='=' read -r key value; do
            key="${key%$'\r'}"
            value="${value%$'\r'}"

            case "$key" in
                ""|\#*)
                    continue
                    ;;
                API_HOST|API_PORT|FRONTEND_PORT|FRONTEND_MODE)
                    export "$key=$value"
                    ;;
            esac
        done < "$env_file"
    fi
}

ensure_log_dir() {
    mkdir -p "$LOG_DIR"
}

check_tcp_connectivity() {
    local host="$1"
    local port="$2"

    if command -v nc > /dev/null 2>&1; then
        nc -z -w 3 "$host" "$port" > /dev/null 2>&1
        return
    fi

    require_python_bootstrap
    "$PYTHON_BOOTSTRAP" - <<PY > /dev/null 2>&1
import socket
import sys

try:
    with socket.create_connection(("${host}", ${port}), timeout=3):
        pass
except Exception:
    sys.exit(1)

sys.exit(0)
PY
}

check_foundation_services() {
    local name
    local port

    for service in \
        "Milvus:19530" \
        "MinIO API:9000" \
        "MinIO Console:9001" \
        "Redis:6379" \
        "PostgreSQL:5432"
    do
        name="${service%%:*}"
        port="${service##*:}"
        if check_tcp_connectivity "$SERVICE_HOST" "$port"; then
            success "${name}: ${SERVICE_HOST}:${port} 可连通"
        else
            warn "${name}: ${SERVICE_HOST}:${port} 不可连通"
        fi
    done
}

print_header() {
    echo ""
    echo -e "${CYAN}========================================${NC}"
    echo -e "${CYAN}  $1${NC}"
    echo -e "${CYAN}========================================${NC}"
    echo ""
}

info() {
    echo -e "${CYAN}$1${NC}"
}

success() {
    echo -e "${GREEN}$1${NC}"
}

warn() {
    echo -e "${YELLOW}$1${NC}"
}

error() {
    echo -e "${RED}$1${NC}" >&2
}

die() {
    error "$1"
    exit 1
}

is_pid_running() {
    local pid="$1"
    [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1
}

read_pid() {
    local pid_file="$1"
    if [ -f "$pid_file" ]; then
        cat "$pid_file"
    fi
}

cleanup_stale_pid() {
    local pid_file="$1"
    local pid
    pid="$(read_pid "$pid_file")"
    if [ -n "$pid" ] && ! is_pid_running "$pid"; then
        rm -f "$pid_file"
    fi
}

port_pid() {
    local port="$1"

    if command -v lsof > /dev/null 2>&1; then
        lsof -ti tcp:"$port" 2>/dev/null | head -n 1 || true
        return 0
    fi

    if command -v ss > /dev/null 2>&1; then
        ss -lptn "sport = :$port" 2>/dev/null | awk -F 'pid=' 'NR>1 && NF>1 {split($2,a,/,/); print a[1]; exit}' || true
        return 0
    fi

    if command -v netstat > /dev/null 2>&1; then
        netstat -lntp 2>/dev/null | awk -v port=":$port" '$4 ~ port {split($7,a,"/"); if (a[1] != "-") {print a[1]; exit}}' || true
    fi

    return 0
}

require_python_bootstrap() {
    if command -v python3 > /dev/null 2>&1; then
        PYTHON_BOOTSTRAP="python3"
    elif command -v python > /dev/null 2>&1; then
        PYTHON_BOOTSTRAP="python"
    else
        die "未找到 Python，请先安装 Python 3.10+。"
    fi
}

require_venv() {
    [ -x "$VENV_PYTHON" ] || die "虚拟环境不存在，请先运行 ./dev.sh setup"
}

ensure_frontend_deps() {
    if [ ! -d "frontend" ]; then
        die "前端目录不存在: frontend"
    fi

    if [ ! -d "frontend/node_modules" ] || [ ! -d "frontend/node_modules/vite" ]; then
        warn "前端依赖不存在或不完整，正在执行 npm install..."
        npm --prefix frontend install
    fi
}

validate_frontend_mode() {
    case "$1" in
        dev|static)
            ;;
        *)
            die "前端模式仅支持 dev 或 static，当前值: $1"
            ;;
    esac
}

check_python_version() {
    local python_cmd="$1"
    "$python_cmd" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)'
}

run_setup() {
    load_env
    ensure_log_dir
    print_header "AI+合规智能中枢 - 环境初始化"

    require_python_bootstrap

    info "[1/4] 检查 Python 版本"
    check_python_version "$PYTHON_BOOTSTRAP" || die "需要 Python 3.10+"
    success "Python 版本检查通过"
    echo ""

    info "[2/4] 准备虚拟环境"
    if [ ! -d "$VENV_DIR" ]; then
        "$PYTHON_BOOTSTRAP" -m venv "$VENV_DIR"
        success "已创建虚拟环境: $VENV_DIR"
    else
        success "虚拟环境已存在: $VENV_DIR"
    fi

    "$VENV_PYTHON" -m pip install --upgrade pip
    "$VENV_PYTHON" -m pip install -r backend/requirements.txt
    success "后端依赖安装完成"
    echo ""

    info "[3/4] 准备前端依赖"
    if ! command -v npm > /dev/null 2>&1; then
        die "未找到 npm，请先安装 Node.js 20+。"
    fi
    npm --prefix frontend install
    success "前端依赖安装完成"
    echo ""

    info "[4/4] 检查 6.86.80.8 基础服务连通性"
    check_foundation_services

    echo ""
    success "环境初始化完成"
    echo "后续常用命令:"
    echo "  ./dev.sh start"
    echo "  ./dev.sh status"
    echo "  ./dev.sh logs api --follow"
}

api_health_ok() {
    if command -v curl > /dev/null 2>&1; then
        curl -fsS "http://${DISPLAY_HOST}:$API_PORT/health" > /dev/null 2>&1
        return
    fi

    require_venv
    "$VENV_PYTHON" - <<PY > /dev/null 2>&1
import sys
from urllib.request import urlopen

try:
    with urlopen("http://${DISPLAY_HOST}:${API_PORT}/health", timeout=3) as response:
        body = response.read().decode("utf-8", errors="ignore")
    sys.exit(0 if "healthy" in body.lower() else 1)
except Exception:
    sys.exit(1)
PY
}

start_api() {
    local mode="${1:-background}"
    load_env
    ensure_log_dir
    require_venv
    cleanup_stale_pid "$API_PID_FILE"

    local pid
    pid="$(read_pid "$API_PID_FILE")"
    if is_pid_running "$pid"; then
        warn "API 已在运行 (PID: $pid)"
        return
    fi

    export PYTHONPATH="backend${PYTHONPATH:+:$PYTHONPATH}"

    if [ "$mode" = "foreground" ]; then
        print_header "AI+合规智能中枢 - 启动 API"
        echo "运行模式: 前台调试（带 --reload）"
        echo "服务地址: http://${DISPLAY_HOST}:$API_PORT"
        echo "文档地址: http://${DISPLAY_HOST}:$API_PORT/docs"
        echo "健康检查: http://${DISPLAY_HOST}:$API_PORT/health"
        echo ""
        exec "$VENV_PYTHON" -m uvicorn app.main:app --host "$API_HOST" --port "$API_PORT" --reload
    fi

    nohup "$VENV_PYTHON" -m uvicorn app.main:app --host "$API_HOST" --port "$API_PORT" > "$API_LOG_FILE" 2>&1 &
    pid=$!
    echo "$pid" > "$API_PID_FILE"
    sleep 3

    if is_pid_running "$pid"; then
        success "API 启动成功 (PID: $pid)"
        echo "  地址: http://${DISPLAY_HOST}:$API_PORT"
        echo "  文档: http://${DISPLAY_HOST}:$API_PORT/docs"
        echo "  日志: $API_LOG_FILE"
    else
        rm -f "$API_PID_FILE"
        die "API 启动失败，请查看日志: $API_LOG_FILE"
    fi
}

start_frontend() {
    local mode="${1:-$FRONTEND_MODE}"
    load_env
    ensure_log_dir
    cleanup_stale_pid "$FRONTEND_PID_FILE"

    local pid
    pid="$(read_pid "$FRONTEND_PID_FILE")"
    if is_pid_running "$pid"; then
        warn "前端已在运行 (PID: $pid)"
        return
    fi

    if ! command -v npm > /dev/null 2>&1; then
        die "未找到 npm，请先安装 Node.js 20+。"
    fi

    ensure_frontend_deps

    if [ "$mode" = "static" ]; then
        require_python_bootstrap
        npm --prefix frontend run build
        nohup "$PYTHON_BOOTSTRAP" -m http.server "$FRONTEND_PORT" --bind 0.0.0.0 --directory frontend/dist > "$FRONTEND_LOG_FILE" 2>&1 &
    else
        nohup npm --prefix frontend run dev -- --host 0.0.0.0 --port "$FRONTEND_PORT" > "$FRONTEND_LOG_FILE" 2>&1 &
    fi

    pid=$!
    echo "$pid" > "$FRONTEND_PID_FILE"
    sleep 4

    if is_pid_running "$pid"; then
        success "前端启动成功 (PID: $pid)"
        echo "  地址: http://${DISPLAY_HOST}:$FRONTEND_PORT"
        echo "  模式: $mode"
        echo "  日志: $FRONTEND_LOG_FILE"
    else
        rm -f "$FRONTEND_PID_FILE"
        die "前端启动失败，请查看日志: $FRONTEND_LOG_FILE"
    fi
}

kill_pid_file_process() {
    local pid_file="$1"
    local label="$2"
    local pid
    pid="$(read_pid "$pid_file")"

    if ! is_pid_running "$pid"; then
        rm -f "$pid_file"
        warn "$label 未通过 PID 文件发现运行中的进程"
        return 1
    fi

    kill "$pid" 2>/dev/null || true
    sleep 2
    if is_pid_running "$pid"; then
        kill -9 "$pid" 2>/dev/null || true
    fi
    rm -f "$pid_file"
    success "$label 已停止"
    return 0
}

stop_api() {
    load_env
    ensure_log_dir

    if kill_pid_file_process "$API_PID_FILE" "API"; then
        return
    fi

    local port_listener
    port_listener="$(port_pid "$API_PORT")"
    if [ -n "$port_listener" ]; then
        kill "$port_listener" 2>/dev/null || true
        sleep 1
        if is_pid_running "$port_listener"; then
            kill -9 "$port_listener" 2>/dev/null || true
        fi
        success "已停止监听 API 端口 $API_PORT 的进程 (PID: $port_listener)"
    else
        warn "未发现运行中的 API 服务"
    fi

    rm -f "$API_PID_FILE"
}

stop_frontend() {
    load_env
    ensure_log_dir

    if kill_pid_file_process "$FRONTEND_PID_FILE" "前端"; then
        return
    fi

    local port_listener
    port_listener="$(port_pid "$FRONTEND_PORT")"
    if [ -n "$port_listener" ]; then
        kill "$port_listener" 2>/dev/null || true
        sleep 1
        if is_pid_running "$port_listener"; then
            kill -9 "$port_listener" 2>/dev/null || true
        fi
        success "已停止监听前端端口 $FRONTEND_PORT 的进程 (PID: $port_listener)"
    else
        warn "未发现运行中的前端服务"
    fi

    rm -f "$FRONTEND_PID_FILE"
}

run_status() {
    load_env
    ensure_log_dir
    print_header "AI+合规智能中枢 - 服务状态"

    cleanup_stale_pid "$API_PID_FILE"
    cleanup_stale_pid "$FRONTEND_PID_FILE"

    local api_running=false
    local frontend_running=false
    local pid
    local port_listener
    local service_name
    local service_port

    echo -e "${YELLOW}API 服务:${NC}"
    pid="$(read_pid "$API_PID_FILE")"
    if is_pid_running "$pid"; then
        api_running=true
        success "  状态: 运行中"
        echo "  PID:    $pid"
    else
        port_listener="$(port_pid "$API_PORT")"
        if [ -n "$port_listener" ]; then
            api_running=true
            success "  状态: 运行中 (无 PID 文件)"
            echo "  PID:    $port_listener"
        else
            error "  状态: 已停止"
        fi
    fi

    if [ "$api_running" = true ]; then
        if api_health_ok; then
            success "  健康检查: 正常"
        else
            warn "  健康检查: 未通过"
        fi
    fi
    echo "  地址:    http://${DISPLAY_HOST}:$API_PORT"
    echo "  文档:    http://${DISPLAY_HOST}:${API_PORT}/docs"
    echo ""

    echo -e "${YELLOW}前端服务:${NC}"
    pid="$(read_pid "$FRONTEND_PID_FILE")"
    if is_pid_running "$pid"; then
        frontend_running=true
        success "  状态: 运行中"
        echo "  PID:    $pid"
    else
        port_listener="$(port_pid "$FRONTEND_PORT")"
        if [ -n "$port_listener" ]; then
            frontend_running=true
            success "  状态: 运行中 (无 PID 文件)"
            echo "  PID:    $port_listener"
        else
            error "  状态: 已停止"
        fi
    fi
    echo "  模式:    $FRONTEND_MODE"
    echo "  地址:    http://${DISPLAY_HOST}:$FRONTEND_PORT"
    echo ""

    echo -e "${YELLOW}基础服务连通性:${NC}"
    for service in \
        "Milvus:19530" \
        "MinIO API:9000" \
        "MinIO Console:9001" \
        "Redis:6379" \
        "PostgreSQL:5432"
    do
        service_name="${service%%:*}"
        service_port="${service##*:}"
        if check_tcp_connectivity "$SERVICE_HOST" "$service_port"; then
            success "  ${service_name}: ${SERVICE_HOST}:${service_port} 可连通"
        else
            warn "  ${service_name}: ${SERVICE_HOST}:${service_port} 不可连通"
        fi
    done

    echo ""
    if [ "$api_running" = true ] && [ "$frontend_running" = true ]; then
        success "所有核心服务均在运行"
    else
        warn "存在未运行的服务，可使用 ./dev.sh start 启动"
    fi
}

run_logs() {
    local target="${1:-}"
    local follow="${2:-}"
    local log_file

    case "$target" in
        api)
            log_file="$API_LOG_FILE"
            ;;
        frontend)
            log_file="$FRONTEND_LOG_FILE"
            ;;
        *)
            die "请指定日志类型: api 或 frontend"
            ;;
    esac

    [ -f "$log_file" ] || die "日志文件不存在: $log_file"

    if [ "$follow" = "--follow" ]; then
        tail -f "$log_file"
    else
        tail -n 50 "$log_file"
    fi
}

show_help() {
    cat <<'EOF'
AI+合规智能中枢统一脚本

用法:
  ./dev.sh help
  ./dev.sh setup
  ./dev.sh start [all|api|frontend|worker|beat] [--foreground] [--mode dev|static]
  ./dev.sh stop [all|api|frontend]
  ./dev.sh restart [all|api|frontend] [--mode dev|static]
  ./dev.sh status
  ./dev.sh logs <api|frontend> [--follow]

命令说明:
  help
    输出完整帮助信息、默认端口、日志目录和常见示例。

  setup
    进行一次性的本地初始化。
    包含 Python 版本检查、.venv 虚拟环境创建、后端依赖安装、前端 npm install、
    以及 6.86.80.8 基础服务端口连通性检查。
    初始化完成后，首次运行前还需执行:
      PYTHONPATH=backend .venv/bin/python scripts/seed_users.py
    以创建 admin/legal/ehs/readonly 四个演示用户。

  start
    启动服务。默认行为等同于 ./dev.sh start all。
    可选目标:
      all       同时启动 API 和前端。
      api       只启动后端 API。
      frontend  只启动前端。
      worker    启动 Celery 文档处理 worker（前台运行，需要 Redis）。
      beat      启动 Celery Beat 定时调度器（前台运行，需要 Redis）。
    可选参数:
      --foreground    仅对 start api 生效，前台运行并开启 --reload，便于调试。
      --mode dev      前端使用 Vite 开发服务器，默认端口 5173。
      --mode static   前端先执行 npm run build，再以静态文件服务器方式启动。

  stop
    停止服务。默认行为等同于 ./dev.sh stop all。
    会优先读取 logs/*.pid，PID 文件失效时会回退到端口探测。
    注意: worker 和 beat 为前台进程，直接 Ctrl+C 停止。

  restart
    先停止再启动，支持 all/api/frontend。
    restart frontend --mode static 可直接切换前端启动模式。

  status
    查看 API、前端、6.86.80.8 基础服务的状态。
    API 状态包含健康检查；前端状态包含当前模式和访问地址。

  logs
    查看日志。默认输出最后 50 行。
    追加 --follow 后会持续跟踪日志输出。

默认约定:
  API_HOST        默认 0.0.0.0
  API_PORT        默认 8000
  FRONTEND_PORT   默认 5173
  FRONTEND_MODE   默认 dev
  日志目录        logs/
  PID 文件        logs/api.pid, logs/frontend.pid

常用示例:
  ./dev.sh setup
  PYTHONPATH=backend .venv/bin/python scripts/seed_users.py
  ./dev.sh start
  ./dev.sh start api --foreground
  ./dev.sh start worker
  ./dev.sh start beat
  ./dev.sh start frontend --mode static
  ./dev.sh restart frontend --mode dev
  ./dev.sh status
  ./dev.sh logs api --follow
  ./dev.sh logs frontend
EOF
}

parse_target() {
    local default_target="$1"
    local candidate="${2:-}"
    case "$candidate" in
        all|api|frontend|worker|beat)
            echo "$candidate"
            ;;
        *)
            echo "$default_target"
            ;;
    esac
}

main() {
    local command="${1:-help}"
    local target="all"
    local mode=""
    local foreground=false
    local log_target=""
    shift || true
    load_env

    case "$command" in
        help|-h|--help)
            show_help
            ;;
        setup)
            run_setup
            ;;
        start)
            target="$(parse_target all "${1:-}")"
            if [ "$target" != "all" ]; then
                shift || true
            fi

            # worker and beat are pass-through — forward remaining args to celery directly.
            case "$target" in
                worker)
                    print_header "AI+合规智能中枢 - 启动 Celery Worker"
                    require_venv
                    export PYTHONPATH="backend${PYTHONPATH:+:$PYTHONPATH}"
                    "$VENV_PYTHON" -m celery -A app.infrastructure.tasks.celery_app worker \
                        --loglevel=info \
                        --concurrency=2 \
                        --queues=celery \
                        "$@"
                    ;;
                beat)
                    print_header "AI+合规智能中枢 - 启动 Celery Beat"
                    require_venv
                    export PYTHONPATH="backend${PYTHONPATH:+:$PYTHONPATH}"
                    "$VENV_PYTHON" -m celery -A app.infrastructure.tasks.celery_app beat \
                        --loglevel=info \
                        "$@"
                    ;;
                *)
                    while [ $# -gt 0 ]; do
                        case "$1" in
                            --foreground)
                                foreground=true
                                ;;
                            --mode)
                                shift || die "--mode 需要指定 dev 或 static"
                                mode="$1"
                                validate_frontend_mode "$mode"
                                ;;
                            *)
                                die "未知参数: $1"
                                ;;
                        esac
                        shift || true
                    done

                    case "$target" in
                        all)
                            [ "$foreground" = false ] || die "start all 不支持 --foreground，请使用 start api --foreground"
                            print_header "AI+合规智能中枢 - 启动服务"
                            start_api background
                            start_frontend "${mode:-$FRONTEND_MODE}"
                            ;;
                        api)
                            if [ "$foreground" = true ]; then
                                start_api foreground
                            else
                                print_header "AI+合规智能中枢 - 启动 API"
                                start_api background
                            fi
                            ;;
                        frontend)
                            print_header "AI+合规智能中枢 - 启动前端"
                            start_frontend "${mode:-$FRONTEND_MODE}"
                            ;;
                    esac
                    ;;
            esac
            ;;
        stop)
            target="$(parse_target all "${1:-}")"
            print_header "AI+合规智能中枢 - 停止服务"
            case "$target" in
                all)
                    stop_frontend
                    stop_api
                    ;;
                api)
                    stop_api
                    ;;
                frontend)
                    stop_frontend
                    ;;
            esac
            ;;
        restart)
            target="$(parse_target all "${1:-}")"
            if [ "$target" != "all" ]; then
                shift || true
            fi
            while [ $# -gt 0 ]; do
                case "$1" in
                    --mode)
                        shift || die "--mode 需要指定 dev 或 static"
                        mode="$1"
                        validate_frontend_mode "$mode"
                        ;;
                    *)
                        die "未知参数: $1"
                        ;;
                esac
                shift || true
            done

            print_header "AI+合规智能中枢 - 重启服务"
            case "$target" in
                all)
                    stop_frontend
                    stop_api
                    start_api background
                    start_frontend "${mode:-$FRONTEND_MODE}"
                    ;;
                api)
                    stop_api
                    start_api background
                    ;;
                frontend)
                    stop_frontend
                    start_frontend "${mode:-$FRONTEND_MODE}"
                    ;;
            esac
            ;;
        status)
            run_status
            ;;
        logs)
            log_target="${1:-}"
            run_logs "$log_target" "${2:-}"
            ;;
        *)
            die "未知命令: $command。可使用 ./dev.sh help 查看帮助。"
            ;;
    esac
}

main "$@"
