#!/bin/bash

PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
FRONTEND_DIR="$PROJECT_DIR/legal-platform-frontend"
BACKEND_DIR="$PROJECT_DIR"
WORKER_SCRIPT="$PROJECT_DIR/scripts/start_worker.sh"
BEAT_SCRIPT="$PROJECT_DIR/scripts/start_beat.sh"
LOG_DIR="$PROJECT_DIR/.codex-run"
BACKEND_PID_FILE="$LOG_DIR/backend.pid"
FRONTEND_PID_FILE="$LOG_DIR/frontend.pid"
WORKER_PID_FILE="$LOG_DIR/worker.pid"
BEAT_PID_FILE="$LOG_DIR/beat.pid"
BACKEND_LOG="$LOG_DIR/backend.log"
FRONTEND_LOG="$LOG_DIR/frontend.log"
WORKER_LOG="$LOG_DIR/worker.log"
BEAT_LOG="$LOG_DIR/beat.log"

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

mkdir -p "$LOG_DIR"

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

resolve_python() {
    local -a candidates=(
        "$PROJECT_DIR/.venv/bin/python"
        "$PROJECT_DIR/.venv/bin/python3"
        "$(command -v python3 2>/dev/null)"
        "$(command -v python 2>/dev/null)"
    )

    local candidate=""
    for candidate in "${candidates[@]}"; do
        if [ -n "$candidate" ] && [ -x "$candidate" ]; then
            echo "$candidate"
            return 0
        fi
    done
    return 1
}

read_env_value() {
    local file=$1
    local key=$2
    if [ -f "$file" ]; then
        awk -F= -v key="$key" '$1 == key {print substr($0, index($0, "=") + 1); exit}' "$file"
    fi
}

FRONTEND_PUBLIC_PORT="$(read_env_value "$FRONTEND_DIR/.env" "PORT")"
FRONTEND_PUBLIC_PORT="${FRONTEND_PUBLIC_PORT:-5173}"
FRONTEND_DEV_PORT=5193

BACKEND_PYTHON="$(resolve_python || true)"
BACKEND_PORT="$("${BACKEND_PYTHON:-python3}" - <<'PY' 2>/dev/null || true
from fastapi_admin.config import APP_PORT
print(APP_PORT)
PY
)"
BACKEND_PORT="${BACKEND_PORT:-8000}"

pid_alive() {
    local pid=$1
    [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null
}

service_pid() {
    local pid_file=$1
    if [ -f "$pid_file" ]; then
        tr -d '[:space:]' < "$pid_file"
    fi
}

cleanup_pid_file() {
    local pid_file=$1
    local pid
    pid=$(service_pid "$pid_file")
    if [ -n "$pid" ] && ! pid_alive "$pid"; then
        rm -f "$pid_file"
    fi
}

port_pid() {
    local port=$1
    local pid=""

    pid=$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | head -n 1)
    if [ -n "$pid" ]; then
        echo "$pid"
        return 0
    fi

    pid=$(ss -ltnp 2>/dev/null | awk -v port=":$port" '
        index($0, port) {
            if (match($0, /pid=[0-9]+/)) {
                value = substr($0, RSTART + 4, RLENGTH - 4)
                print value
                exit
            }
        }
    ')

    [ -n "$pid" ] && echo "$pid"
}

pid_command() {
    local pid=$1
    ps -p "$pid" -o args= 2>/dev/null | xargs
}

kill_process_tree() {
    local pid=$1
    [ -n "$pid" ] || return 0

    local children
    children=$(pgrep -P "$pid" 2>/dev/null || true)
    if [ -n "$children" ]; then
        local child
        for child in $children; do
            kill_process_tree "$child"
        done
    fi

    kill "$pid" 2>/dev/null || true
}

ensure_port_free() {
    local name=$1
    local port=$2
    local expected_pid=${3:-}
    local running_pid

    running_pid=$(port_pid "$port")
    if [ -n "$running_pid" ] && [ "$running_pid" != "$expected_pid" ]; then
        local cmd
        cmd="$(pid_command "$running_pid")"
        log_error "$name 目标端口 $port 已被其他进程占用 (PID: $running_pid)"
        [ -n "$cmd" ] && log_error "占用进程命令: $cmd"
        return 1
    fi
    return 0
}

start_backend() {
    cleanup_pid_file "$BACKEND_PID_FILE"
    local pid
    pid=$(service_pid "$BACKEND_PID_FILE")
    if pid_alive "$pid"; then
        log_warn "后端已在运行 (PID: $pid)"
        return 0
    fi

    ensure_port_free "后端" "$BACKEND_PORT" || return 1

    if [ -z "$BACKEND_PYTHON" ]; then
        log_error "未找到可用 Python"
        return 1
    fi

    log_info "启动后端服务 (端口: $BACKEND_PORT)..."
    : > "$BACKEND_LOG"
    (
        cd "$BACKEND_DIR"
        exec "$BACKEND_PYTHON" run.py
    ) >> "$BACKEND_LOG" 2>&1 &
    pid=$!
    sleep 2

    local listening_pid
    listening_pid=$(port_pid "$BACKEND_PORT")
    if pid_alive "$pid" || [ -n "$listening_pid" ]; then
        echo "${listening_pid:-$pid}" > "$BACKEND_PID_FILE"
        log_success "后端启动成功 (PID: $pid, 端口: $BACKEND_PORT)"
        return 0
    fi

    log_error "后端启动失败，查看日志: $BACKEND_LOG"
    tail -20 "$BACKEND_LOG" 2>/dev/null || true
    rm -f "$BACKEND_PID_FILE"
    return 1
}

start_frontend() {
    cleanup_pid_file "$FRONTEND_PID_FILE"
    local pid
    pid=$(service_pid "$FRONTEND_PID_FILE")
    if pid_alive "$pid"; then
        log_warn "前端已在运行 (PID: $pid)"
        return 0
    fi

    ensure_port_free "前端开发服务" "$FRONTEND_DEV_PORT" || return 1

    log_info "启动前端开发服务 (端口: $FRONTEND_DEV_PORT，代理入口: $FRONTEND_PUBLIC_PORT)..."
    : > "$FRONTEND_LOG"
    (
        cd "$FRONTEND_DIR"
        exec npm run dev:dev
    ) >> "$FRONTEND_LOG" 2>&1 &
    pid=$!
    sleep 4

    local listening_pid
    listening_pid=$(port_pid "$FRONTEND_DEV_PORT")
    if pid_alive "$pid" || [ -n "$listening_pid" ]; then
        echo "${listening_pid:-$pid}" > "$FRONTEND_PID_FILE"
        log_success "前端启动成功 (PID: $pid, 开发端口: $FRONTEND_DEV_PORT, 访问端口: $FRONTEND_PUBLIC_PORT)"
        return 0
    fi

    log_error "前端启动失败，查看日志: $FRONTEND_LOG"
    tail -20 "$FRONTEND_LOG" 2>/dev/null || true
    rm -f "$FRONTEND_PID_FILE"
    return 1
}

start_worker() {
    cleanup_pid_file "$WORKER_PID_FILE"
    local pid
    pid=$(service_pid "$WORKER_PID_FILE")
    if pid_alive "$pid"; then
        log_warn "Worker 已在运行 (PID: $pid)"
        return 0
    fi

    if [ ! -x "$WORKER_SCRIPT" ]; then
        log_error "Worker 启动脚本不存在或不可执行: $WORKER_SCRIPT"
        return 1
    fi

    log_info "启动 Worker 服务..."
    : > "$WORKER_LOG"
    (
        cd "$PROJECT_DIR"
        exec "$WORKER_SCRIPT"
    ) >> "$WORKER_LOG" 2>&1 &
    pid=$!
    echo "$pid" > "$WORKER_PID_FILE"
    sleep 2

    if pid_alive "$pid"; then
        log_success "Worker 启动成功 (PID: $pid)"
        return 0
    fi

    log_error "Worker 启动失败，查看日志: $WORKER_LOG"
    tail -20 "$WORKER_LOG" 2>/dev/null || true
    rm -f "$WORKER_PID_FILE"
    return 1
}

start_beat() {
    cleanup_pid_file "$BEAT_PID_FILE"
    local pid
    pid=$(service_pid "$BEAT_PID_FILE")
    if pid_alive "$pid"; then
        log_warn "Beat 已在运行 (PID: $pid)"
        return 0
    fi

    if [ ! -x "$BEAT_SCRIPT" ]; then
        log_error "Beat 启动脚本不存在或不可执行: $BEAT_SCRIPT"
        return 1
    fi

    log_info "启动 Beat 调度服务..."
    : > "$BEAT_LOG"
    (
        cd "$PROJECT_DIR"
        exec "$BEAT_SCRIPT"
    ) >> "$BEAT_LOG" 2>&1 &
    pid=$!
    echo "$pid" > "$BEAT_PID_FILE"
    sleep 2

    if pid_alive "$pid"; then
        log_success "Beat 启动成功 (PID: $pid)"
        return 0
    fi

    log_error "Beat 启动失败，查看日志: $BEAT_LOG"
    tail -20 "$BEAT_LOG" 2>/dev/null || true
    rm -f "$BEAT_PID_FILE"
    return 1
}

stop_service() {
    local name=$1
    local pid_file=$2
    local port=${3:-}
    local pid
    pid=$(service_pid "$pid_file")

    if ! pid_alive "$pid"; then
        if [ -n "$port" ]; then
            local stray_pid
            stray_pid=$(port_pid "$port")
            if [ -n "$stray_pid" ]; then
                log_warn "$name PID 文件已失效，正在清理端口 $port 上的残留进程 (PID: $stray_pid)..."
                kill_process_tree "$stray_pid"
                sleep 1
                if pid_alive "$stray_pid"; then
                    kill -9 "$stray_pid" 2>/dev/null || true
                fi
                rm -f "$pid_file"
                log_success "$name 残留进程已停止"
                return 0
            fi
        fi
        rm -f "$pid_file"
        log_warn "$name 未运行"
        return 0
    fi

    log_info "停止 $name (PID: $pid)..."
    kill_process_tree "$pid"
    for _ in $(seq 1 10); do
        local current_port_pid=""
        if [ -n "$port" ]; then
            current_port_pid=$(port_pid "$port")
        fi
        if ! pid_alive "$pid" && [ -z "$current_port_pid" ]; then
            break
        fi
        sleep 0.5
    done
    local stubborn_pid=""
    if [ -n "$port" ]; then
        stubborn_pid=$(port_pid "$port")
    fi
    if pid_alive "$pid" || [ -n "$stubborn_pid" ]; then
        log_warn "$name 未响应，强制终止..."
        kill -9 "$pid" 2>/dev/null || true
        [ -n "$stubborn_pid" ] && kill -9 "$stubborn_pid" 2>/dev/null || true
    fi
    rm -f "$pid_file"
    log_success "$name 已停止"
}

do_start() {
    echo ""
    echo -e "${CYAN}============================================${NC}"
    echo -e "${CYAN}  启动 LeAudit 前后端${NC}"
    echo -e "${CYAN}============================================${NC}"
    echo ""

    start_backend || return 1
    start_frontend || return 1
    start_worker || return 1
    start_beat || return 1

    echo ""
    echo -e "${GREEN}============================================${NC}"
    echo -e "${GREEN}  前端: http://localhost:$FRONTEND_PUBLIC_PORT (开发服务: $FRONTEND_DEV_PORT)${NC}"
    echo -e "${GREEN}  后端: http://localhost:$BACKEND_PORT${NC}"
    echo -e "${GREEN}  Worker: $WORKER_SCRIPT${NC}"
    echo -e "${GREEN}  Beat: $BEAT_SCRIPT${NC}"
    echo -e "${GREEN}  日志目录: $LOG_DIR${NC}"
    echo -e "${GREEN}============================================${NC}"
    echo ""
}

do_stop() {
    echo ""
    echo -e "${YELLOW}============================================${NC}"
    echo -e "${YELLOW}  停止 LeAudit 前后端${NC}"
    echo -e "${YELLOW}============================================${NC}"
    echo ""
    stop_service "Beat" "$BEAT_PID_FILE"
    stop_service "Worker" "$WORKER_PID_FILE"
    stop_service "前端" "$FRONTEND_PID_FILE" "$FRONTEND_DEV_PORT"
    stop_service "后端" "$BACKEND_PID_FILE" "$BACKEND_PORT"
    echo ""
}

do_restart() {
    do_stop
    sleep 1
    do_start
}

do_status() {
    cleanup_pid_file "$BACKEND_PID_FILE"
    cleanup_pid_file "$FRONTEND_PID_FILE"
    cleanup_pid_file "$WORKER_PID_FILE"
    cleanup_pid_file "$BEAT_PID_FILE"

    echo ""
    echo -e "${CYAN}============================================${NC}"
    echo -e "${CYAN}  服务状态${NC}"
    echo -e "${CYAN}============================================${NC}"
    echo ""

    local pid
    pid=$(service_pid "$BACKEND_PID_FILE")
    if pid_alive "$pid"; then
        echo -e "  后端:  ${GREEN}● 运行中${NC}  PID=$pid  端口=$BACKEND_PORT"
    else
        echo -e "  后端:  ${RED}○ 已停止${NC}"
    fi

    pid=$(service_pid "$FRONTEND_PID_FILE")
    if pid_alive "$pid"; then
        echo -e "  前端:  ${GREEN}● 运行中${NC}  PID=$pid  开发端口=$FRONTEND_DEV_PORT  访问端口=$FRONTEND_PUBLIC_PORT"
    else
        echo -e "  前端:  ${RED}○ 已停止${NC}"
    fi

    pid=$(service_pid "$WORKER_PID_FILE")
    if pid_alive "$pid"; then
        echo -e "  Worker: ${GREEN}● 运行中${NC}  PID=$pid"
    else
        echo -e "  Worker: ${RED}○ 已停止${NC}"
    fi

    pid=$(service_pid "$BEAT_PID_FILE")
    if pid_alive "$pid"; then
        echo -e "  Beat:   ${GREEN}● 运行中${NC}  PID=$pid"
    else
        echo -e "  Beat:   ${RED}○ 已停止${NC}"
    fi

    echo ""
    echo "  后端日志: $BACKEND_LOG"
    echo "  前端日志: $FRONTEND_LOG"
    echo "  Worker日志: $WORKER_LOG"
    echo "  Beat日志: $BEAT_LOG"
    echo ""
}

do_logs() {
    local target=${2:-all}
    local lines=${3:-100}

    case "$target" in
        backend)
            [ -f "$BACKEND_LOG" ] || touch "$BACKEND_LOG"
            echo -e "${CYAN}--- 后端日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$BACKEND_LOG"
            echo -e "${CYAN}--- Ctrl+C 退出 ---${NC}"
            tail -f "$BACKEND_LOG"
            ;;
        frontend)
            [ -f "$FRONTEND_LOG" ] || touch "$FRONTEND_LOG"
            echo -e "${CYAN}--- 前端日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$FRONTEND_LOG"
            echo -e "${CYAN}--- Ctrl+C 退出 ---${NC}"
            tail -f "$FRONTEND_LOG"
            ;;
        worker)
            [ -f "$WORKER_LOG" ] || touch "$WORKER_LOG"
            echo -e "${CYAN}--- Worker 日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$WORKER_LOG"
            echo -e "${CYAN}--- Ctrl+C 退出 ---${NC}"
            tail -f "$WORKER_LOG"
            ;;
        beat)
            [ -f "$BEAT_LOG" ] || touch "$BEAT_LOG"
            echo -e "${CYAN}--- Beat 日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$BEAT_LOG"
            echo -e "${CYAN}--- Ctrl+C 退出 ---${NC}"
            tail -f "$BEAT_LOG"
            ;;
        all)
            [ -f "$BACKEND_LOG" ] || touch "$BACKEND_LOG"
            [ -f "$FRONTEND_LOG" ] || touch "$FRONTEND_LOG"
            [ -f "$WORKER_LOG" ] || touch "$WORKER_LOG"
            [ -f "$BEAT_LOG" ] || touch "$BEAT_LOG"
            echo -e "${CYAN}--- 后端日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$BACKEND_LOG"
            echo ""
            echo -e "${CYAN}--- 前端日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$FRONTEND_LOG"
            echo ""
            echo -e "${CYAN}--- Worker 日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$WORKER_LOG"
            echo ""
            echo -e "${CYAN}--- Beat 日志 (最近 $lines 行) ---${NC}"
            tail -n "$lines" "$BEAT_LOG"
            echo ""
            echo -e "${CYAN}--- Ctrl+C 退出 ---${NC}"
            tail -n 0 -f "$BACKEND_LOG" "$FRONTEND_LOG" "$WORKER_LOG" "$BEAT_LOG" 2>/dev/null | awk '
                /^==> .*backend\.log <==$/ { current="[backend]"; next }
                /^==> .*frontend\.log <==$/ { current="[frontend]"; next }
                /^==> .*worker\.log <==$/ { current="[worker]"; next }
                /^==> .*beat\.log <==$/ { current="[beat]"; next }
                { print current " " $0; fflush() }
            '
            ;;
        *)
            echo "用法: ./leaudit.sh logs [backend|frontend|worker|beat|all] [行数]"
            exit 1
            ;;
    esac
}

do_doctor() {
    echo ""
    echo -e "${CYAN}============================================${NC}"
    echo -e "${CYAN}  运行环境检查${NC}"
    echo -e "${CYAN}============================================${NC}"
    echo ""

    local pid cmd

    pid=$(port_pid "$FRONTEND_PUBLIC_PORT")
    if [ -n "$pid" ]; then
        cmd="$(pid_command "$pid")"
        echo -e "  代理端口 5173: ${GREEN}● 已监听${NC}  PID=$pid"
        [ -n "$cmd" ] && echo "    命令: $cmd"
    else
        echo -e "  代理端口 5173: ${RED}○ 未监听${NC}"
    fi

    pid=$(port_pid "$FRONTEND_DEV_PORT")
    if [ -n "$pid" ]; then
        cmd="$(pid_command "$pid")"
        echo -e "  前端开发 5193: ${GREEN}● 已监听${NC}  PID=$pid"
        [ -n "$cmd" ] && echo "    命令: $cmd"
    else
        echo -e "  前端开发 5193: ${RED}○ 未监听${NC}"
    fi

    pid=$(port_pid "$BACKEND_PORT")
    if [ -n "$pid" ]; then
        cmd="$(pid_command "$pid")"
        echo -e "  后端服务 $BACKEND_PORT: ${GREEN}● 已监听${NC}  PID=$pid"
        [ -n "$cmd" ] && echo "    命令: $cmd"
    else
        echo -e "  后端服务 $BACKEND_PORT: ${RED}○ 未监听${NC}"
    fi

    local worker_pid
    worker_pid=$(service_pid "$WORKER_PID_FILE")
    if pid_alive "$worker_pid"; then
        cmd="$(pid_command "$worker_pid")"
        echo -e "  Worker 进程: ${GREEN}● 运行中${NC}  PID=$worker_pid"
        [ -n "$cmd" ] && echo "    命令: $cmd"
    else
        echo -e "  Worker 进程: ${RED}○ 未运行${NC}"
    fi

    local beat_pid
    beat_pid=$(service_pid "$BEAT_PID_FILE")
    if pid_alive "$beat_pid"; then
        cmd="$(pid_command "$beat_pid")"
        echo -e "  Beat 进程:   ${GREEN}● 运行中${NC}  PID=$beat_pid"
        [ -n "$cmd" ] && echo "    命令: $cmd"
    else
        echo -e "  Beat 进程:   ${RED}○ 未运行${NC}"
    fi

    echo ""
}

do_open() {
    echo ""
    echo -e "${CYAN}============================================${NC}"
    echo -e "${CYAN}  访问地址与日志摘要${NC}"
    echo -e "${CYAN}============================================${NC}"
    echo ""
    echo "  前端访问: http://localhost:$FRONTEND_PUBLIC_PORT"
    echo "  前端开发: http://127.0.0.1:$FRONTEND_DEV_PORT"
    echo "  后端访问: http://localhost:$BACKEND_PORT"
    echo "  Worker脚本: $WORKER_SCRIPT"
    echo "  Beat脚本: $BEAT_SCRIPT"
    echo ""
    echo -e "${CYAN}--- 后端最近 5 行 ---${NC}"
    tail -n 5 "$BACKEND_LOG" 2>/dev/null || echo "(无后端日志)"
    echo ""
    echo -e "${CYAN}--- 前端最近 5 行 ---${NC}"
    tail -n 5 "$FRONTEND_LOG" 2>/dev/null || echo "(无前端日志)"
    echo ""
    echo -e "${CYAN}--- Worker最近 5 行 ---${NC}"
    tail -n 5 "$WORKER_LOG" 2>/dev/null || echo "(无Worker日志)"
    echo ""
    echo -e "${CYAN}--- Beat最近 5 行 ---${NC}"
    tail -n 5 "$BEAT_LOG" 2>/dev/null || echo "(无Beat日志)"
    echo ""
}

case "${1:-help}" in
    start)
        do_start
        ;;
    stop)
        do_stop
        ;;
    restart)
        do_restart
        ;;
    status)
        do_status
        ;;
    logs)
        do_logs "$@"
        ;;
    doctor)
        do_doctor
        ;;
    open)
        do_open
        ;;
    help|--help|-h)
        echo "用法: ./leaudit.sh <命令>"
        echo ""
        echo "命令说明:"
        echo "  start              启动前后端、Worker、Beat"
        echo "  stop               停止前后端、Worker、Beat"
        echo "  restart            重启前后端、Worker、Beat"
        echo "  status             查看前后端、Worker、Beat 运行状态"
        echo "  logs               查看前后端、Worker、Beat 日志并持续跟踪"
        echo "  logs backend       只看后端日志"
        echo "  logs frontend 50   看前端最近 50 行日志并持续跟踪"
        echo "  logs worker 50     看 Worker 最近 50 行日志并持续跟踪"
        echo "  logs beat 50       看 Beat 最近 50 行日志并持续跟踪"
        echo "  doctor             检查 5173 / 5193 / 8096 端口占用情况"
        echo "  open               打印访问地址和最近日志摘要"
        echo ""
        echo "示例:"
        echo "  ./leaudit.sh start"
        echo "  ./leaudit.sh status"
        echo "  ./leaudit.sh logs"
        echo "  ./leaudit.sh doctor"
        echo "  ./leaudit.sh open"
        ;;
    *)
        log_error "未知命令: $1"
        echo "运行 ./leaudit.sh help 查看帮助"
        exit 1
        ;;
esac
