# -*- coding: utf-8 -*-
import subprocess
import sys
import time
import os

# 服务器配置
SERVER_HOST = "45.249.208.118"
SERVER_USER = "root"
SERVER_PASSWORD = "lxvhNYFZ4160"
SERVER_PROJECT_DIR = "/root/youyidian-3d"
LOCAL_PACKAGE = "project-deploy.tar.gz"

def print_step(step, message):
    print(f"\n{'='*60}")
    print(f"步骤 {step}: {message}")
    print('='*60)

def run_ssh_command(command):
    """执行SSH命令"""
    full_cmd = f'ssh {SERVER_USER}@{SERVER_HOST} "{command}"'
    print(f"\n执行命令: {command}\n")
    
    # 使用 plink 或 ssh (需要手动输入密码)
    result = subprocess.run(full_cmd, shell=True, capture_output=False, text=True)
    return result.returncode == 0

def main():
    print("\n" + "="*60)
    print("     FLNXI素材库系统 - 自动部署脚本")
    print(f"     目标服务器: {SERVER_HOST}")
    print("="*60)
    
    # 检查部署包是否存在
    if not os.path.exists(LOCAL_PACKAGE):
        print(f"\n[ERROR] Cannot find: {LOCAL_PACKAGE}")
        print("Please create package first")
        return False
    
    file_size = os.path.getsize(LOCAL_PACKAGE) / 1024 / 1024
    print(f"\n[OK] Found package: {LOCAL_PACKAGE} ({file_size:.2f} MB)")
    
    # 步骤1: 上传文件
    print_step(1, "上传部署包到服务器")
    print(f"正在上传 {LOCAL_PACKAGE} 到 {SERVER_HOST}:/root/")
    print(f"密码: {SERVER_PASSWORD}")
    print("\n请在提示时输入密码...")
    time.sleep(2)
    
    upload_cmd = f"scp {LOCAL_PACKAGE} {SERVER_USER}@{SERVER_HOST}:/root/"
    result = subprocess.run(upload_cmd, shell=True)
    
    if result.returncode != 0:
        print("\n[ERROR] Upload failed!")
        return False
    
    print("\n[OK] Upload success!")
    
    # 步骤2: 创建项目目录
    print_step(2, "创建项目目录")
    commands = [
        f"mkdir -p {SERVER_PROJECT_DIR}",
        f"cd {SERVER_PROJECT_DIR} && pwd"
    ]
    
    for cmd in commands:
        print(f"执行: {cmd}")
    
    result = subprocess.run(
        f'ssh {SERVER_USER}@{SERVER_HOST} "{"; ".join(commands)}"',
        shell=True
    )
    
    # 步骤3: 备份现有文件
    print_step(3, "备份现有上传文件")
    backup_cmd = f"""
cd {SERVER_PROJECT_DIR} && \
if [ -d uploads ]; then \
    mkdir -p backups && \
    echo '正在备份uploads目录...' && \
    cp -r uploads backups/uploads-$(date +%Y%m%d-%H%M%S) 2>/dev/null || true && \
    echo '[OK] Backup complete'; \
else \
    echo '[WARN] No uploads directory found, skip backup'; \
fi
"""
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "{backup_cmd}"', shell=True)
    
    # 步骤4: 解压文件
    print_step(4, "解压新版本")
    extract_cmd = f"""
cd {SERVER_PROJECT_DIR} && \
echo '正在解压项目文件...' && \
tar -xzf /root/{LOCAL_PACKAGE} && \
rm /root/{LOCAL_PACKAGE} && \
echo '[OK] Extract complete' && \
ls -lh
"""
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "{extract_cmd}"', shell=True)
    
    # 步骤5: 恢复上传目录
    print_step(5, "恢复上传目录")
    restore_cmd = f"""
cd {SERVER_PROJECT_DIR} && \
if [ -d backups ]; then \
    latest=$(ls -td backups/uploads-* 2>/dev/null | head -1); \
    if [ -n "$latest" ]; then \
        echo "从 $latest 恢复上传文件..."; \
        mkdir -p uploads; \
        cp -r "$latest"/* uploads/ 2>/dev/null || true; \
        echo '[OK] Restore complete'; \
    fi; \
fi && \
mkdir -p uploads && \
chmod -R 777 uploads && \
echo '[OK] Permissions set'
"""
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "{restore_cmd}"', shell=True)
    
    # 步骤6: 查看当前Docker状态
    print_step(6, "检查Docker状态")
    subprocess.run(
        f'ssh {SERVER_USER}@{SERVER_HOST} "docker ps -a"',
        shell=True
    )
    
    # 步骤7: 停止旧容器
    print_step(7, "停止旧容器")
    stop_cmd = f"""
cd {SERVER_PROJECT_DIR} && \
echo '正在停止旧容器...' && \
docker compose down 2>/dev/null || docker-compose down 2>/dev/null || true && \
echo '[OK] Old containers stopped'
"""
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "{stop_cmd}"', shell=True)
    
    # 步骤8: 构建并启动新容器
    print_step(8, "构建并启动新容器")
    print("[WARN] This step may take several minutes, please wait...")
    build_cmd = f"""
cd {SERVER_PROJECT_DIR} && \
echo '正在构建镜像...' && \
docker compose up -d --build --force-recreate || docker-compose up -d --build --force-recreate && \
echo '[OK] Containers started'
"""
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "{build_cmd}"', shell=True)
    
    # 步骤9: 等待容器启动
    print_step(9, "等待容器完全启动")
    print("等待20秒...")
    for i in range(20, 0, -1):
        print(f"\r剩余 {i} 秒...", end="", flush=True)
        time.sleep(1)
    print("\n")
    
    # 步骤10: 数据库迁移
    print_step(10, "执行数据库迁移")
    migrate_cmd = f"""
cd {SERVER_PROJECT_DIR} && \
echo '正在执行数据库迁移...' && \
docker compose exec -T app npx prisma db push --accept-data-loss --schema=/app/prisma/schema.prisma 2>/dev/null || \
docker-compose exec -T app npx prisma db push --accept-data-loss --schema=/app/prisma/schema.prisma 2>/dev/null || \
echo '[WARN] Database migration failed, may need manual execution'
"""
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "{migrate_cmd}"', shell=True)
    
    # 步骤11: 查看最终状态
    print_step(11, "查看部署结果")
    print("\n容器运行状态:")
    subprocess.run(f'ssh {SERVER_USER}@{SERVER_HOST} "docker ps"', shell=True)
    
    print("\n\n应用日志（最后30行）:")
    subprocess.run(
        f'ssh {SERVER_USER}@{SERVER_HOST} "cd {SERVER_PROJECT_DIR} && (docker compose logs --tail=30 app 2>/dev/null || docker-compose logs --tail=30 app)"',
        shell=True
    )
    
    # 完成
    print("\n" + "="*60)
    print("     [OK] Deployment Complete!")
    print("="*60)
    print(f"\n访问地址: http://{SERVER_HOST}:端口号")
    print("(请根据docker-compose.yml中的端口配置访问)")
    print("\n常用命令:")
    print(f"  查看日志: ssh {SERVER_USER}@{SERVER_HOST} 'cd {SERVER_PROJECT_DIR} && docker compose logs -f app'")
    print(f"  重启服务: ssh {SERVER_USER}@{SERVER_HOST} 'cd {SERVER_PROJECT_DIR} && docker compose restart'")
    print(f"  停止服务: ssh {SERVER_USER}@{SERVER_HOST} 'cd {SERVER_PROJECT_DIR} && docker compose down'")
    print("="*60)
    
    return True

if __name__ == "__main__":
    try:
        success = main()
        sys.exit(0 if success else 1)
    except KeyboardInterrupt:
        print("\n\n[INFO] User interrupted")
        sys.exit(1)
    except Exception as e:
        print(f"\n\n[ERROR] Error occurred: {e}")
        sys.exit(1)


