#!/bin/bash

# QAUP 离线部署镜像准备脚本
# 此脚本需要在有网络连接的环境中运行，用于准备离线部署所需的所有镜像

set -e

# 显示帮助信息
show_help() {
    echo "QAUP 离线部署镜像准备脚本"
    echo ""
    echo "用法: $0 [选项]"
    echo ""
    echo "选项:"
    echo "  -h, --help     显示帮助信息"
    echo "  --no-build     跳过自定义镜像构建（仅拉取基础镜像）"
    echo "  --clean        清理现有的离线部署目录"
    echo ""
    echo "功能:"
    echo "  - 自动检测 docker-compose.yml 中的镜像版本"
    echo "  - 拉取所有必需的基础镜像"
    echo "  - 构建 QAUP 自定义镜像"
    echo "  - 导出所有镜像为 tar.gz 文件"
    echo "  - 生成校验和文件"
    echo "  - 创建导入脚本和部署包"
    echo ""
    echo "系统要求:"
    echo "  - Docker 已安装并运行"
    echo "  - 网络连接正常"
    echo "  - 足够的磁盘空间（建议 10GB+）"
}

# 检查参数
NO_BUILD=false
CLEAN=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        --no-build)
            NO_BUILD=true
            shift
            ;;
        --clean)
            CLEAN=true
            shift
            ;;
        *)
            echo "未知选项: $1"
            show_help
            exit 1
            ;;
    esac
done

# 检查 Docker 是否可用
if ! command -v docker &> /dev/null; then
    echo "错误: Docker 未安装或不在 PATH 中"
    exit 1
fi

if ! docker info &> /dev/null; then
    echo "错误: Docker 服务未运行"
    exit 1
fi

# 配置变量
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
IMAGES_DIR="$PROJECT_ROOT/offline-deploy/images"
CONFIG_DIR="$PROJECT_ROOT/offline-deploy/config"
SCRIPTS_DIR="$PROJECT_ROOT/offline-deploy/scripts"

# 加载镜像版本配置
IMAGE_VERSIONS_FILE="$SCRIPT_DIR/image-versions.env"

if [ -f "$IMAGE_VERSIONS_FILE" ]; then
    echo "从配置文件加载镜像版本: $IMAGE_VERSIONS_FILE"
    source "$IMAGE_VERSIONS_FILE"
else
    echo "警告: 镜像版本配置文件不存在，使用默认版本"
    # 默认版本（如果配置文件不存在）
    POSTGRES_IMAGE="postgis/postgis:16-3.4"
    REDIS_IMAGE="redis:7.2-alpine"
    OPENJDK_IMAGE="openjdk:21-jre-slim"
    MAVEN_IMAGE="maven:3.9-openjdk-21-slim"
    NGINX_IMAGE="nginx:1.25-alpine"
    NODE_IMAGE="node:20-alpine"
    QAUP_APP_IMAGE="qaup-app:latest"
    QAUP_NGINX_IMAGE="qaup-nginx:latest"
fi

echo "使用的镜像版本:"
echo "  PostgreSQL/PostGIS: $POSTGRES_IMAGE"
echo "  Redis: $REDIS_IMAGE"
echo "  Maven: $MAVEN_IMAGE"
echo "  OpenJDK: $OPENJDK_IMAGE"
echo "  Nginx: $NGINX_IMAGE"
echo "  Node.js: $NODE_IMAGE"
echo "  QAUP App: $QAUP_APP_IMAGE"
echo "  QAUP Nginx: $QAUP_NGINX_IMAGE"
echo ""

# 检查是否需要更新 docker-compose.yml 和 Dockerfile
echo "检查配置文件同步状态..."
COMPOSE_POSTGRES=$(grep -A 1 "qaup-postgres:" "$PROJECT_ROOT/docker-compose.yml" | grep "image:" | awk '{print $2}' | head -1)
COMPOSE_REDIS=$(grep -A 1 "qaup-redis:" "$PROJECT_ROOT/docker-compose.yml" | grep "image:" | awk '{print $2}' | head -1)

if [ "$COMPOSE_POSTGRES" != "$POSTGRES_IMAGE" ]; then
    echo "警告: docker-compose.yml 中的 PostgreSQL 版本 ($COMPOSE_POSTGRES) 与配置文件不一致 ($POSTGRES_IMAGE)"
fi

if [ "$COMPOSE_REDIS" != "$REDIS_IMAGE" ]; then
    echo "警告: docker-compose.yml 中的 Redis 版本 ($COMPOSE_REDIS) 与配置文件不一致 ($REDIS_IMAGE)"
fi
echo ""

# 自定义镜像名称
QAUP_APP_IMAGE="qaup-app:latest"
QAUP_NGINX_IMAGE="qaup-nginx:latest"

echo "========================================="
echo "QAUP 离线部署镜像准备开始"
echo "========================================="

# 清理现有目录（如果需要）
if [ "$CLEAN" = true ] && [ -d "$PROJECT_ROOT/offline-deploy" ]; then
    echo "清理现有离线部署目录..."
    rm -rf "$PROJECT_ROOT/offline-deploy"
fi

# 创建目录结构
echo "创建离线部署目录结构..."
mkdir -p "$IMAGES_DIR" "$CONFIG_DIR" "$SCRIPTS_DIR"

# 拉取基础镜像函数
pull_image() {
    local image=$1
    echo "拉取镜像: $image"
    if docker pull "$image"; then
        echo "✓ $image 拉取成功"
    else
        echo "✗ $image 拉取失败"
        exit 1
    fi
}

# 拉取基础镜像
echo "拉取基础镜像..."
pull_image "$OPENJDK_IMAGE"
pull_image "$NGINX_IMAGE"
pull_image "$POSTGRES_IMAGE"
pull_image "$REDIS_IMAGE"
pull_image "$NODE_IMAGE"
pull_image "$MAVEN_IMAGE"

# 构建自定义镜像
echo "构建 QAUP 应用镜像..."
cd "$PROJECT_ROOT"
if docker build -f deploy/Dockerfile -t $QAUP_APP_IMAGE .; then
    echo "✓ QAUP 应用镜像构建成功"
else
    echo "✗ QAUP 应用镜像构建失败"
    exit 1
fi

echo "构建 QAUP Nginx 镜像..."
if docker build -f deploy/docker/nginx/Dockerfile -t $QAUP_NGINX_IMAGE .; then
    echo "✓ QAUP Nginx 镜像构建成功"
else
    echo "✗ QAUP Nginx 镜像构建失败"
    exit 1
fi

# 导出镜像函数
export_image() {
    local image=$1
    local filename=$2
    echo "导出镜像: $image -> $filename"
    if docker save "$image" | gzip > "$IMAGES_DIR/$filename"; then
        echo "✓ $filename 导出成功"
    else
        echo "✗ $filename 导出失败"
        exit 1
    fi
}

# 导出镜像文件
echo "导出镜像文件..."
export_image "$OPENJDK_IMAGE" "openjdk-17-jre-slim.tar.gz"
export_image "$NGINX_IMAGE" "nginx-alpine.tar.gz"
export_image "$POSTGRES_IMAGE" "postgis.tar.gz"
export_image "$REDIS_IMAGE" "redis-alpine.tar.gz"
export_image "$NODE_IMAGE" "node-alpine.tar.gz"
export_image "$MAVEN_IMAGE" "maven-openjdk.tar.gz"
export_image "$QAUP_APP_IMAGE" "qaup-app.tar.gz"
export_image "$QAUP_NGINX_IMAGE" "qaup-nginx.tar.gz"

# 创建镜像清单文件
echo "创建镜像清单..."
cat > "$IMAGES_DIR/images-list.txt" << EOF
# QAUP 离线部署镜像清单
# 生成时间: $(date)
# 生成主机: $(hostname)

# 基础镜像
openjdk-17-jre-slim.tar.gz -> $OPENJDK_IMAGE
nginx-alpine.tar.gz -> $NGINX_IMAGE
postgis.tar.gz -> $POSTGRES_IMAGE
redis-alpine.tar.gz -> $REDIS_IMAGE
node-alpine.tar.gz -> $NODE_IMAGE
maven-openjdk.tar.gz -> $MAVEN_IMAGE

# 自定义镜像
qaup-app.tar.gz -> $QAUP_APP_IMAGE
qaup-nginx.tar.gz -> $QAUP_NGINX_IMAGE

# 使用说明
# 1. 将所有 .tar.gz 文件复制到目标服务器
# 2. 运行 load-images.sh 脚本导入镜像
# 3. 验证校验和: sha256sum -c checksums.sha256
EOF

# 创建镜像导入脚本
echo "创建镜像导入脚本..."
cat > "$SCRIPTS_DIR/load-images.sh" << 'EOF'
#!/bin/bash

# QAUP 离线镜像导入脚本
# 在目标服务器上运行此脚本导入镜像

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
IMAGES_DIR="$SCRIPT_DIR/../images"

echo "========================================="
echo "QAUP 离线镜像导入开始"
echo "========================================="

# 检查镜像文件
if [ ! -d "$IMAGES_DIR" ]; then
    echo "错误: 镜像目录不存在: $IMAGES_DIR"
    exit 1
fi

# 验证校验和
if [ -f "$IMAGES_DIR/checksums.sha256" ]; then
    echo "验证文件校验和..."
    cd "$IMAGES_DIR"
    if sha256sum -c checksums.sha256; then
        echo "✓ 文件校验和验证通过"
    else
        echo "✗ 文件校验和验证失败"
        exit 1
    fi
    cd - > /dev/null
fi

# 导入镜像
echo "导入镜像文件..."
for image_file in "$IMAGES_DIR"/*.tar.gz; do
    if [ -f "$image_file" ]; then
        echo "导入: $(basename "$image_file")"
        if gunzip -c "$image_file" | docker load; then
            echo "✓ $(basename "$image_file") 导入成功"
        else
            echo "✗ $(basename "$image_file") 导入失败"
            exit 1
        fi
    fi
done

echo ""
echo "========================================="
echo "镜像导入完成！"
echo "========================================="
echo "已导入的镜像:"
docker images | grep -E "(qaup|postgres|redis|nginx|openjdk|node|maven)"
EOF

# 设置执行权限
chmod +x "$SCRIPTS_DIR/load-images.sh"

# 计算文件大小和校验和
echo "计算文件校验和..."
cd "$IMAGES_DIR"
sha256sum *.tar.gz > checksums.sha256

# 显示统计信息
echo ""
echo "========================================="
echo "镜像准备完成统计信息:"
echo "========================================="
echo "镜像文件数量: $(ls -1 *.tar.gz | wc -l)"
echo "总大小: $(du -sh . | cut -f1)"
echo ""
echo "镜像文件列表:"
ls -lh *.tar.gz
echo ""
echo "校验和文件已生成: checksums.sha256"
# 复制必要的配置文件到根目录
echo "复制配置文件..."
cp "$PROJECT_ROOT/deploy/docker-compose.yml" "$PROJECT_ROOT/offline-deploy/"
cp "$PROJECT_ROOT/deploy/docker-compose.prod.yml" "$PROJECT_ROOT/offline-deploy/"
cp "$PROJECT_ROOT/deploy/.env.template" "$PROJECT_ROOT/offline-deploy/"

# 创建config目录并复制application-prod.yml
echo "复制应用配置文件..."
mkdir -p "$PROJECT_ROOT/offline-deploy/config"
cp "$PROJECT_ROOT/deploy/config/application-prod.yml" "$PROJECT_ROOT/offline-deploy/config/"

# 复制部署脚本
cp "$PROJECT_ROOT/deploy/deploy.sh" "$SCRIPTS_DIR/"

# 复制docker配置目录
echo "复制Docker配置..."
mkdir -p "$PROJECT_ROOT/offline-deploy/docker"
cp -r "$PROJECT_ROOT/deploy/docker"/* "$PROJECT_ROOT/offline-deploy/docker/" 2>/dev/null || true

# 复制文档
echo "复制文档..."
mkdir -p "$PROJECT_ROOT/offline-deploy/docs"
cp -r "$PROJECT_ROOT/deploy/docs"/* "$PROJECT_ROOT/offline-deploy/docs/" 2>/dev/null || true

# 复制数据库脚本（如果存在）
if [ -d "$PROJECT_ROOT/sql" ]; then
    echo "复制数据库脚本..."
    cp -r "$PROJECT_ROOT/sql" "$PROJECT_ROOT/offline-deploy/"
fi

# 创建离线部署说明
cat > "$PROJECT_ROOT/offline-deploy/README-离线部署.md" << 'EOF'
# QAUP 离线部署包

## 包含内容

- `images/` - Docker 镜像文件
- `scripts/` - 部署脚本
- `docker/` - Docker配置和数据库初始化脚本
- `docs/` - 部署文档
- `sql/` - 数据库架构文件（如果存在）
- `docker-compose.yml` - Docker Compose 主配置文件
- `docker-compose.prod.yml` - 生产环境配置文件
- `.env.template` - 环境变量模板文件

## 重要文件说明

### 配置文件
- `docker-compose.yml` - Docker Compose 主配置文件
- `docker-compose.prod.yml` - 生产环境特定配置
- `.env.template` - 环境变量配置模板

### 数据库初始化数据
- `docker/postgres/export/01_system_data.sql` - 系统基础数据
- `docker/postgres/export/02_business_data.sql` - 业务数据
- `docker/postgres/export/03_sample_data.sql` - 示例数据
- `docker/postgres/export/initial_data_complete.sql` - 完整初始化数据

## 部署步骤

1. 将整个 `offline-deploy` 目录复制到目标服务器
2. 进入部署目录：`cd offline-deploy`
3. 导入镜像：`./scripts/load-images.sh`
4. 配置环境：`cp .env.template .env` 并根据实际情况编辑 `.env` 文件
5. 启动服务：`./scripts/deploy.sh install`

## 手动部署方式

如果使用部署脚本遇到问题，可以手动执行：

```bash
# 1. 导入镜像
./scripts/load-images.sh

# 2. 配置环境变量
cp .env.template .env
# 编辑 .env 文件，设置数据库密码、端口等配置

# 3. 启动服务
docker-compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env up -d

# 4. 查看服务状态
docker-compose -f docker-compose.yml -f docker-compose.prod.yml ps

# 5. 查看日志
docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f
```

## 系统要求

- Docker 20.10+
- Docker Compose 1.29+
- 至少 4GB 内存
- 至少 20GB 磁盘空间

## 数据库初始化

系统启动时会自动执行数据库初始化脚本，按以下顺序：
1. 系统数据（用户、角色、权限等）
2. 业务数据（机场配置、区域设置等）
3. 示例数据（测试用途，可选）

## 常见问题

### 端口冲突
如果遇到端口被占用的问题，请修改 `.env` 文件中的端口配置：
- `NGINX_PORT` - Nginx HTTP 端口（默认 80）
- `NGINX_HTTPS_PORT` - Nginx HTTPS 端口（默认 443）
- `APP_PORT` - 应用端口（默认 8080）

### 权限问题
如果遇到数据目录权限问题，请执行：
```bash
sudo chown -R $USER:$USER data/
sudo chmod -R 755 data/
```

### 服务管理
```bash
# 停止服务
docker-compose -f docker-compose.yml -f docker-compose.prod.yml down

# 重启服务
docker-compose -f docker-compose.yml -f docker-compose.prod.yml restart

# 查看特定服务日志
docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f qaup-app
```
EOF

# 创建离线部署包
echo "创建离线部署包..."
cd "$PROJECT_ROOT"
PACKAGE_NAME="qaup-offline-deploy-$(date +%Y%m%d_%H%M%S).tar.gz"
tar -czf "$PACKAGE_NAME" offline-deploy/

echo ""
echo "========================================="
echo "离线部署准备完成！"
echo "========================================="
echo "镜像文件位置: $IMAGES_DIR"
echo "配置文件位置: $CONFIG_DIR"
echo "脚本文件位置: $SCRIPTS_DIR"
echo "离线部署包: $PROJECT_ROOT/$PACKAGE_NAME"
echo ""
echo "部署包大小: $(du -sh "$PROJECT_ROOT/$PACKAGE_NAME" | cut -f1)"
echo ""
echo "使用方法:"
echo "1. 将 $PACKAGE_NAME 传输到目标服务器"
echo "2. 解压: tar -xzf $PACKAGE_NAME"
echo "3. 按照 offline-deploy/README-离线部署.md 中的说明进行部署"