# -*- coding: utf-8 -*-
"""
deploy_docker.py - Docker 部署到 192.168.5.60 服务器

部署目录: /data/third_party/monitor-platform
"""

import paramiko
import os
import time
from datetime import datetime

# SSH 配置
HOST = os.environ.get('SSH_HOST', '192.168.5.60')
USER = os.environ.get('SSH_USER', 'ubains')
PASSWORD = os.environ.get('SSH_PASSWORD', '')
REMOTE_BASE = '/data/third_party/monitor-platform'

if not PASSWORD:
    print("错误：SSH_PASSWORD 环境变量未设置")
    print("用法: SSH_PASSWORD='xxx' python deploy_docker.py")
    exit(1)

# 本地仓库根目录
REPO_ROOT = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))

# 需要上传的目录（相对于仓库根目录）
DIRS_TO_UPLOAD = [
    ('skill/code/web', 'skill/code/web'),
    ('skill/code/requirements.txt', 'skill/code/requirements.txt'),
    ('skill/SKILL.md', 'skill/SKILL.md'),
    ('frontend/dist', 'frontend/dist'),
    ('nginx', 'nginx'),
    ('config', 'config'),
    ('Docs/维护手册', 'Docs/维护手册'),  # 产品维护手册（离线模式下载）
]

# 需要上传的单个文件
FILES_TO_UPLOAD = [
    ('Dockerfile', 'Dockerfile'),
    ('docker-compose.yml', 'docker-compose.yml'),
    ('.env', '.env'),
    ('deploy/搜索索引.json', 'data/搜索索引.json'),
]

# 排除目录
_EXCLUDE_DIRS = {'__pycache__', 'tests', 'data', '.pytest_cache', 'node_modules', '.git'}
_EXCLUDE_SUFFIXES = ('.pyc', '.pyo', '.log')


def _upload_dir_recursive(sftp, ssh, local_dir, remote_dir):
    """递归上传目录（使用 pathlib 处理中文文件名）"""
    from pathlib import Path

    local_path = Path(local_dir)

    # 确保远程目录存在
    ssh.exec_command(f'mkdir -p "{remote_dir}"')[1].channel.recv_exit_status()

    for child in sorted(local_path.iterdir()):
        fname = child.name
        if fname in _EXCLUDE_DIRS:
            continue
        if fname.endswith(_EXCLUDE_SUFFIXES):
            continue

        rpath = remote_dir + "/" + fname

        if child.is_file():
            try:
                rel = os.path.relpath(str(child), REPO_ROOT)
                print(f"  Upload: {rel}")
                sftp.put(str(child), rpath)
            except (PermissionError, OSError) as e:
                print(f"  [SKIP] {rel} ({e})")
        elif child.is_dir():
            _upload_dir_recursive(sftp, ssh, str(child), rpath)


def deploy():
    print("=" * 60)
    print("  Troubleshoot - Docker Deploy")
    print("=" * 60)
    print(f"Server: {HOST}")
    print(f"User: {USER}")
    print(f"Remote: {REMOTE_BASE}")
    print("=" * 60)

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        print("\n[1/5] Connecting...")
        ssh.connect(HOST, username=USER, password=PASSWORD)
        print("[OK] Connected")

        print("\n[2/5] Preparing directories...")
        # 确保目标目录存在
        ssh.exec_command(f'sudo mkdir -p {REMOTE_BASE}')[1].channel.recv_exit_status()
        ssh.exec_command(f'sudo chown -R ubains:ubains {REMOTE_BASE}')[1].channel.recv_exit_status()

        # 创建必要的子目录
        for _, remote_rel in DIRS_TO_UPLOAD:
            remote_dir = f"{REMOTE_BASE}/{remote_rel}"
            ssh.exec_command(f'mkdir -p "{remote_dir}"')[1].channel.recv_exit_status()

        print("[OK] Directories prepared")

        print("\n[3/5] Uploading files...")
        sftp = ssh.open_sftp()

        # 上传目录
        for local_rel, remote_rel in DIRS_TO_UPLOAD:
            local_path = os.path.join(REPO_ROOT, local_rel)
            remote_path = f"{REMOTE_BASE}/{remote_rel}"

            if not os.path.exists(local_path):
                print(f"  [SKIP] {local_rel} (not found)")
                continue

            if os.path.isfile(local_path):
                print(f"  Upload: {local_rel}")
                sftp.put(local_path, remote_path)
            else:
                print(f"  Upload dir: {local_rel}/")
                _upload_dir_recursive(sftp, ssh, local_path, remote_path)

        # 上传单个文件
        for local_rel, remote_rel in FILES_TO_UPLOAD:
            local_path = os.path.join(REPO_ROOT, local_rel)
            remote_path = f"{REMOTE_BASE}/{remote_rel}"

            if not os.path.exists(local_path):
                print(f"  [SKIP] {local_rel} (not found)")
                continue

            # 确保父目录存在
            parent_dir = os.path.dirname(remote_path)
            ssh.exec_command(f'mkdir -p "{parent_dir}"')[1].channel.recv_exit_status()

            print(f"  Upload: {local_rel}")
            sftp.put(local_path, remote_path)

        sftp.close()
        print("[OK] Files uploaded")

        print("\n[4/5] Building Docker image...")
        stdin, stdout, stderr = ssh.exec_command(f'cd {REMOTE_BASE} && sudo docker build -t troubleshoot:latest . 2>&1')
        build_output = stdout.read().decode()
        if 'Successfully tagged' in build_output:
            print("[OK] Image built successfully")
        else:
            print(build_output[-500:] if len(build_output) > 500 else build_output)
            # 检查是否只是警告
            if 'ERROR' in build_output:
                print("[FAIL] Build failed")
                return

        print("\n[5/5] Starting container...")
        # 停止旧容器
        stdin, stdout, stderr = ssh.exec_command('sudo docker stop troubleshoot 2>/dev/null; sudo docker rm troubleshoot 2>/dev/null; echo done')
        stdout.read()

        # 启动新容器
        run_cmd = f'''sudo docker run -d --name troubleshoot --restart unless-stopped \\
  --add-host=host.docker.internal:host-gateway \\
  -p 8088:80 \\
  -v {REMOTE_BASE}/monitor-data:/app/web/service_monitor/data \\
  -v {REMOTE_BASE}/data/users.json:/app/web/users.json \\
  -v {REMOTE_BASE}/data/搜索索引.json:/app/data/搜索索引.json:ro \\
  -v {REMOTE_BASE}/frontend/dist:/data/dist \\
  -v {REMOTE_BASE}/logs:/app/web/logs \\
  --env-file {REMOTE_BASE}/.env \\
  troubleshoot:latest'''

        stdin, stdout, stderr = ssh.exec_command(run_cmd)
        container_id = stdout.read().decode().strip()
        err = stderr.read().decode()
        if err:
            print(f"Error: {err}")

        if container_id:
            print(f"[OK] Container started: {container_id[:12]}")
        else:
            print("[FAIL] Container start failed")
            return

        print("\n[6/6] Verifying...")
        time.sleep(5)

        stdin, stdout, stderr = ssh.exec_command('curl -s http://localhost:8088/api/health')
        result = stdout.read().decode()

        if result and '"status":"ok"' in result:
            print("[OK] Service is running")
            print(f"\nHealth check:")
            print(result[:400])
        else:
            print("[FAIL] Service may not be running")
            stdin, stdout, stderr = ssh.exec_command('sudo docker logs troubleshoot --tail 30')
            print(stdout.read().decode())

        print("\n" + "=" * 60)
        print("  Deployment Complete!")
        print("=" * 60)
        print(f"URL: http://{HOST}:8088")
        print(f"Health: http://{HOST}:8088/api/health")
        print(f"Deploy dir: {REMOTE_BASE}")
        print("=" * 60)

    except Exception as e:
        print(f"\n[ERROR] {e}")
        import traceback
        traceback.print_exc()

    finally:
        ssh.close()


if __name__ == '__main__':
    deploy()