#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：deploy_fix_560.py
模块描述：把「新建会议 step 11/17 修复」部署到生产 5.60。

部署内容：
1. scp 覆盖 backend/app/executors/playwright_executor.py（策略5 轮询勾选修复）
2. scp 上传 scripts/fix_step12.py / run_case_verify.py
3. 服务器上运行 fix_step12.py 更新生产用例 step 12（保持立即开始）
4. docker restart plat-auto-test-app（加载新执行器）
5. 触发生产用例执行 2-3 次验收

用法：
    python scripts/deploy_fix_560.py [--runs 3]
作者：czj
创建日期：2026-08-19
"""
import argparse
import os
import sys
import time

sys.stdout.reconfigure(encoding="utf-8")

import paramiko

HOST = "192.168.5.60"
USER = "ubains"
PASS = "Ubains@123"
APP_DIR = "/data/third_party/plat-auto-test"
BACKEND_HOST = "/data/third_party/plat-auto-test/backend"
CONTAINER = "plat-auto-test-app"
PROD_CASE = "case_13650e0406e64779b66e6fa5de35c24a"

# 本地 → 服务器路径
UPLOADS = [
    ("app/executors/playwright_executor.py", BACKEND_HOST + "/app/executors/playwright_executor.py"),
    ("scripts/fix_step12.py", BACKEND_HOST + "/scripts/fix_step12.py"),
    ("scripts/run_case_verify.py", BACKEND_HOST + "/scripts/run_case_verify.py"),
]

LOCAL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # backend/


def ssh_exec(client, cmd, timeout=300):
    stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout)
    out = stdout.read().decode("utf-8", errors="replace")
    err = stderr.read().decode("utf-8", errors="replace")
    return out, err


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--runs", type=int, default=3, help="生产验收执行次数")
    parser.add_argument("--no-restart", action="store_true", help="跳过 docker restart")
    parser.add_argument("--no-fix", action="store_true", help="跳过 fix_step12 更新")
    args = parser.parse_args()

    print(f"== 连接 {HOST} ==")
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(HOST, username=USER, password=PASS, timeout=30)

    # 1. 上传文件
    print("\n== 1. scp 上传 ==")
    sftp = client.open_sftp()
    for local_rel, remote in UPLOADS:
        local = os.path.join(LOCAL_ROOT, local_rel)
        sftp.put(local, remote)
        size = os.path.getsize(local)
        print(f"  {local_rel} -> {remote} ({size}B)")
    sftp.close()

    # 2. 更新生产用例 step 12
    if not args.no_fix:
        print("\n== 2. 更新生产用例 step 12 ==")
        cmd = (
            f"cd {BACKEND_HOST} && python3 scripts/fix_step12.py "
            f"--base http://localhost --case {PROD_CASE}"
        )
        out, err = ssh_exec(client, cmd, timeout=120)
        print(out)
        if err.strip():
            print("[stderr]", err[:500])

    # 3. 重启容器加载新执行器
    if not args.no_restart:
        print("\n== 3. docker restart ==")
        out, err = ssh_exec(client, f"docker restart {CONTAINER}", timeout=180)
        print(out.strip() or err.strip()[:200])
        time.sleep(12)
        # 健康检查
        for i in range(10):
            out, _ = ssh_exec(client, "curl -s http://localhost/health", timeout=30)
            if out.strip():
                print(f"  健康检查({i+1}): {out.strip()[:100]}")
                break
            time.sleep(5)
        else:
            print("  !! 健康检查未通过")

    # 4. 生产验收执行
    print(f"\n== 4. 生产验收：执行 {args.runs} 次 ==")
    for i in range(1, args.runs + 1):
        print(f"\n----- 第 {i}/{args.runs} 次 -----")
        cmd = (
            f"cd {BACKEND_HOST} && python3 scripts/run_case_verify.py "
            f"--base http://localhost --case {PROD_CASE}"
        )
        out, err = ssh_exec(client, cmd, timeout=600)
        print(out)
        if err.strip():
            print("[stderr]", err[:300])

    client.close()
    print("\n== 部署验收完成 ==")


if __name__ == "__main__":
    main()
