#!/bin/bash
# Jingrow 统一开发脚本

set -e

# 获取脚本所在目录（项目根目录）
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" || exit 1

# 项目路径常量
JINGROW_APP_DIR="apps/jingrow"
FRONTEND_DIR="$JINGROW_APP_DIR/frontend"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 打印函数
info() { echo -e "${BLUE}ℹ${NC} $1"; }
success() { echo -e "${GREEN}✓${NC} $1"; }
warn() { echo -e "${YELLOW}⚠${NC} $1"; }
error() { echo -e "${RED}✗${NC} $1"; }

# 检查命令是否存在
check_cmd() {
    if ! command -v "$1" &> /dev/null; then
        error "$1 未安装"
        return 1
    fi
}

# 安装 uv（官方安装脚本）
install_uv() {
    info "尝试自动安装 uv..."
    # 使用仓库内脚本进行安装
    if [ -f ./install_uv.sh ]; then
        bash ./install_uv.sh || {
            warn "install_uv.sh 执行失败"
            return 1
        }
    else
        warn "install_uv.sh 不存在"
        return 1
    fi

    # 尝试把本次会话的 PATH 补上
    export PATH="$HOME/.local/bin:$PATH"
    # 如果 uv 安装脚本生成了会话环境文件，则立刻激活
    if [ -f "$HOME/.local/bin/env" ]; then
        # shellcheck disable=SC1090
        source "$HOME/.local/bin/env"
    fi

    if command -v uv &> /dev/null; then
        success "uv 安装完成"
        return 0
    fi
    return 1
}

# 安装 Redis
install_redis() {
    info "尝试自动安装 Redis..."
    
    local pkg_manager=""
    local pkg_name=""
    local install_cmd=""
    
    # 检测包管理器
    if command -v apt-get &> /dev/null; then
        pkg_manager="apt-get"
        pkg_name="redis-server"
        install_cmd="apt-get update && apt-get install -y $pkg_name"
    elif command -v yum &> /dev/null; then
        pkg_manager="yum"
        pkg_name="redis"
        install_cmd="yum install -y $pkg_name"
    elif command -v dnf &> /dev/null; then
        pkg_manager="dnf"
        pkg_name="redis"
        install_cmd="dnf install -y $pkg_name"
    else
        error "未检测到支持的包管理器（apt-get/yum/dnf），请手动安装 Redis"
        return 1
    fi
    
    # 执行安装（自动处理 root 权限）
    if [ "$EUID" -eq 0 ]; then
        eval "$install_cmd" || {
            error "$pkg_manager 安装 Redis 失败"
            return 1
        }
    else
        warn "需要 root 权限安装 Redis，尝试使用 sudo..."
        if ! sudo bash -c "$install_cmd"; then
            error "sudo 安装 Redis 失败，请手动安装: sudo $install_cmd"
            return 1
        fi
    fi
    
    # 验证安装
    if command -v redis-server &> /dev/null; then
        success "Redis 安装完成"
        return 0
    else
        error "Redis 安装后未找到 redis-server 命令"
        return 1
    fi
}

# 安装前端依赖
install_frontend_deps() {
    local reason="${1:-前端依赖}"
    info "安装$reason..."
    (cd "$FRONTEND_DIR" && npm install) || {
        error "$reason安装失败"
        return 1
    }
}

# 清理进程
cleanup() {
    info "清理现有进程..."
    pkill -f "uvicorn.*jingrow.main:app" 2>/dev/null || true
    pkill -f "concurrently" 2>/dev/null || true
    pkill -f "dramatiq.*jingrow.services.queue" 2>/dev/null || true
    pkill -f "vite" 2>/dev/null || true
    sleep 1
    
    # 强制释放端口
    if lsof -ti:9001 &> /dev/null; then
        warn "释放端口 9001..."
        lsof -ti:9001 | xargs kill -9 2>/dev/null || true
    fi
    if lsof -ti:3002 &> /dev/null; then
        warn "释放端口 3002..."
        lsof -ti:3002 | xargs kill -9 2>/dev/null || true
    fi
    success "清理完成"
}

# 确保 uv 可用：最先执行
ensure_uv() {
    if command -v uv &> /dev/null; then
        return 0
    fi
    warn "uv 未安装，将尝试自动安装"
    install_uv || {
        error "自动安装 uv 失败，请手动安装: curl -fsSL https://astral.sh/uv/install.sh | sh"
        exit 1
    }
    # 再次兜底激活环境，确保当前会话可用
    if [ -f "$HOME/.local/bin/env" ]; then
        # shellcheck disable=SC1090
        source "$HOME/.local/bin/env"
    fi
}

# 检查Redis
check_redis() {
    if redis-cli ping &> /dev/null; then
        success "Redis 已运行"
        return 0
    fi
    
    # 检查 redis-server 是否安装
    if ! command -v redis-server &> /dev/null; then
        warn "redis-server 未安装，将尝试自动安装"
        install_redis || {
            error "自动安装 Redis 失败，请根据系统手动安装: sudo apt-get install -y redis-server (Ubuntu/Debian) 或 sudo yum install -y redis (CentOS/RHEL)"
            return 1
        }
    fi
    
    warn "Redis 未运行，尝试启动..."
    if command -v redis-server &> /dev/null; then
        redis-server ./redis.conf &> /dev/null &
        sleep 2
        if redis-cli ping &> /dev/null; then
            success "Redis 启动成功"
            return 0
        fi
    fi
    
    error "Redis 未运行，请手动启动: redis-server"
    return 1
}

# 检查依赖
check_deps() {
    info "检查依赖..."
    
    check_cmd node || exit 1
    # 这里假设 ensure_uv 已经在更早阶段被调用
    check_cmd uv || exit 1
    
    # 检查前端依赖
    if [ ! -d "$FRONTEND_DIR/node_modules" ]; then
        warn "前端依赖未安装"
        install_frontend_deps "前端依赖" || exit 1
    fi
    
    # 即使 node_modules 存在，也校验 vite 是否可用（可能之前安装不完整）
    if [ ! -x "$FRONTEND_DIR/node_modules/.bin/vite" ]; then
        warn "未检测到 vite，可执行文件缺失，重新安装前端依赖..."
        install_frontend_deps "前端依赖" || exit 1
    fi
    
    # 检查后端依赖（优先使用 uv）
    info "同步后端依赖 (uv)..."
    if [ -f "$JINGROW_APP_DIR/pyproject.toml" ]; then
        # 同步主项目依赖
        (cd "$JINGROW_APP_DIR" && uv sync) || {
            error "uv 同步失败"
            exit 1
        }
        # 安装所有节点的依赖（使用异步并行安装，提升性能）
        info "安装节点依赖..."
        (cd "$JINGROW_APP_DIR" && uv run python -c "from jingrow.utils.node_dependencies import install_all_nodes_dependencies; install_all_nodes_dependencies(max_concurrent=5)" 2>&1) || {
            warn "安装节点依赖失败，但继续执行"
        }
    elif [ -f "$JINGROW_APP_DIR/requirements.txt" ]; then
        warn "未发现 pyproject.toml，使用 requirements.txt 安装"
        (cd "$JINGROW_APP_DIR" && uv pip install -r requirements.txt) || {
            error "uv pip 安装失败"
            exit 1
        }
    else
        warn "未发现依赖清单（pyproject.toml 或 requirements.txt）"
    fi
    
    success "依赖检查完成"
}

# 构建热重载目录参数（返回热重载参数，日志输出到stderr）
# 使用 --reload-include 模式，自动监听 apps 目录下所有 .py 文件，支持动态安装
build_reload_dirs() {
    local RELOAD_DIRS=""
    local APPS_DIR="apps"
    
    if [ -d "$APPS_DIR" ]; then
        # 监听整个 apps 目录，自动包含新安装的 app（支持热重载）
        RELOAD_DIRS="--reload-dir $(cd "$APPS_DIR" && pwd)"
        info "已启用 apps 目录热重载（自动监听所有 app）" >&2
    else
        warn "apps 目录不存在" >&2
    fi
    
    echo "$RELOAD_DIRS"
}

# 检查并增加 inotify 限制
check_inotify_limit() {
    local current_limit=$(cat /proc/sys/fs/inotify/max_user_watches 2>/dev/null || echo "0")
    local min_limit=524288
    
    if [ "$current_limit" -lt "$min_limit" ]; then
        warn "inotify 限制较低 ($current_limit)，尝试增加到 $min_limit..."
        
        # 临时增加限制（需要 root 权限）
        if sudo sysctl fs.inotify.max_user_watches=$min_limit 2>/dev/null; then
            success "inotify 限制已临时增加到 $min_limit"
        else
            warn "无法自动增加 inotify 限制（需要 root 权限）"
            warn "请手动运行: sudo sysctl -w fs.inotify.max_user_watches=524288"
            warn "或永久设置: echo 'fs.inotify.max_user_watches=524288' | sudo tee -a /etc/sysctl.conf"
        fi
    fi
}

# 启动所有服务
start_all() {
    info "启动开发环境..."
    ensure_uv
    cleanup
    check_inotify_limit
    check_redis
    check_deps
    
    # 加载环境变量
    if [ -f .env ]; then
        export $(grep -v '^#' .env | xargs)
    fi
    
    # 构建热重载目录参数
    RELOAD_DIRS=$(build_reload_dirs)
    
    info "启动所有服务..."
    # 使用延迟启动，让后端先启动3秒
    npx --yes concurrently \
        --names "BACKEND,WORKER,FRONTEND" \
        --prefix-colors "blue,yellow,green" \
        "cd $JINGROW_APP_DIR && uv run python -m jingrow.app" \
        "cd $JINGROW_APP_DIR && uv run python -m jingrow.dramatiq" \
        "sleep 3 && cd $FRONTEND_DIR && npm run dev"
}

# 只启动前端
start_frontend() {
    info "启动前端..."
    ensure_uv
    cleanup
    check_deps
    (cd "$FRONTEND_DIR" && npm run dev)
}

# 只启动后端
start_backend() {
    info "启动后端..."
    ensure_uv
    cleanup
    check_redis
    check_deps
    
    if [ -f .env ]; then
        export $(grep -v '^#' .env | xargs)
    fi
    
    # 构建热重载目录参数
    RELOAD_DIRS=$(build_reload_dirs)
    
    npx --yes concurrently \
        --names "BACKEND,WORKER" \
        --prefix-colors "blue,yellow" \
        "cd $JINGROW_APP_DIR && uv run python -m jingrow.app" \
        "cd $JINGROW_APP_DIR && uv run python -m jingrow.dramatiq"
}

# 停止服务
stop_all() {
    info "停止所有服务..."
    cleanup
    success "已停止"
}

# 重启服务
restart() {
    stop_all
    sleep 2
    start_all
}

# 主函数
main() {
    case "${1:-start}" in
        start)
            start_all
            ;;
        stop)
            stop_all
            ;;
        restart)
            restart
            ;;
        frontend)
            start_frontend
            ;;
        backend)
            start_backend
            ;;
        *)
            echo "用法: ./dev.sh [start|stop|restart|frontend|backend]"
            echo ""
            echo "命令:"
            echo "  start     启动所有服务（默认）"
            echo "  stop      停止所有服务"
            echo "  restart   重启所有服务"
            echo "  frontend  只启动前端"
            echo "  backend   只启动后端"
            exit 1
            ;;
    esac
}

main "$@"

