#!/usr/bin/env python3
"""
CI健康度每日巡检报告脚本
- 调用ci_health_check.py获取数据
- 有失败时生成飞书卡片通知并发送
- 无失败时静默退出（不打扰）
- 用于每日定时巡检

用法:
  python3 scripts/ci/ci_health_report.py [--limit 30] [--dry-run]

环境变量:
  GITEA_TOKEN         API token（必需）
  CI_NOTIFY_WEBHOOK   飞书webhook地址（必需，用于发报告）
  GITEA_API_URL       Gitea API 地址
  GITEA_REPO          仓库
"""

import argparse
import json
import os
import subprocess
import sys
import urllib.request
from datetime import datetime, timedelta, timezone


def run_health_check(limit: int) -> dict:
    """调用ci_health_check.py获取JSON结果"""
    script_dir = os.path.dirname(os.path.abspath(__file__))
    cmd = [
        sys.executable,
        os.path.join(script_dir, "ci_health_check.py"),
        "--json",
        "--limit",
        str(limit),
    ]
    env = os.environ.copy()
    # 确保GITEA_TOKEN传递
    if not env.get("GITEA_TOKEN") and env.get("GITHUB_TOKEN"):
        env["GITEA_TOKEN"] = env["GITHUB_TOKEN"]

    result = subprocess.run(cmd, capture_output=True, text=True, env=env)
    if result.returncode != 0:
        print(f"health check failed: {result.stderr}")
        return {"workflows": {}, "failed_runs": []}
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        print(f"failed to parse health check output: {result.stdout[:200]}")
        return {"workflows": {}, "failed_runs": []}


def build_feishu_card(data: dict) -> dict:
    """构建飞书卡片消息"""
    wf_stats = data.get("workflows", {})
    failed_runs = data.get("failed_runs", [])

    # 统计数据
    total_all = sum(s["total"] for s in wf_stats.values())
    succ_all = sum(s["success"] for s in wf_stats.values())
    fail_all = sum(s["failure"] for s in wf_stats.values())
    rate_all = (succ_all / total_all * 100) if total_all > 0 else 0

    # 失败分类
    infra_fail = 0
    biz_fail = 0
    unknown_fail = 0
    for run in failed_runs:
        for job in run.get("jobs", []):
            cat = job.get("category", "unknown")
            if cat == "infra":
                infra_fail += 1
            elif cat == "business":
                biz_fail += 1
            else:
                unknown_fail += 1

    now = datetime.now(timezone(timedelta(hours=8))).strftime("%Y-%m-%d %H:%M")

    # 各workflow成功率行
    wf_lines = []
    for wf, s in sorted(wf_stats.items()):
        total = s["total"]
        succ = s["success"]
        fail = s["failure"]
        rate = (succ / total * 100) if total > 0 else 0
        icon = "🟢" if rate >= 90 else ("🟡" if rate >= 70 else "🔴")
        wf_name = (
            wf.replace("ci-pipeline.yml", "CI Pipeline")
            .replace("code-review.yml", "Code Review")
            .replace("daily-check.yml", "Daily Check")
            .replace("preview-deploy.yml", "Preview Deploy")
        )
        wf_lines.append(f"{icon} **{wf_name}**: {rate:.0f}% ({succ}/{total}，失败{fail})")

    # 失败详情（最多显示5条）
    fail_detail_lines = []
    for _i, run in enumerate(failed_runs[:5]):
        run_id = run["id"]
        title = run.get("title", "")[:35]
        branch = run.get("branch", "")
        jobs_str = ", ".join(j["name"][:15] for j in run.get("jobs", [])[:3])
        fail_detail_lines.append(f"• **#{run_id}** {title}\n   分支: {branch} | 失败: {jobs_str}")

    if len(failed_runs) > 5:
        fail_detail_lines.append(f"... 还有 {len(failed_runs) - 5} 条失败记录")

    # 整体状态
    if fail_all == 0:
        status_text = "✅ 全部通过"
        status_color = "green"
    elif infra_fail > biz_fail:
        status_text = "⚠️ 基础设施问题为主"
        status_color = "yellow"
    else:
        status_text = "🔴 存在业务失败"
        status_color = "red"

    card = {
        "config": {"wide_screen_mode": True},
        "header": {
            "title": {"tag": "plain_text", "content": f"CI告警 - 每日健康度巡检 ({now})"},
            "template": status_color,
        },
        "elements": [
            {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": f"**统计范围**: 最近 {total_all} 条 run\n**整体状态**: {status_text}\n**总成功率**: {rate_all:.1f}% ({succ_all}/{total_all})",
                },
            },
            {"tag": "hr"},
            {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": "**📊 各Workflow成功率**\n" + "\n".join(wf_lines) if wf_lines else "暂无数据",
                },
            },
        ],
    }

    # 失败分类统计
    if fail_all > 0:
        card["elements"].append({"tag": "hr"})
        card["elements"].append(
            {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": f"**失败原因分类**\n🏗️ 基础设施: {infra_fail} 个\n🐛 业务代码: {biz_fail} 个\n❓ 待确认: {unknown_fail} 个",
                },
            }
        )

    # 失败详情
    if fail_detail_lines:
        card["elements"].append({"tag": "hr"})
        card["elements"].append(
            {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": "**❌ 失败详情**\n" + "\n\n".join(fail_detail_lines),
                },
            }
        )

    # 查看更多
    card["elements"].append({"tag": "hr"})
    base_url = os.environ.get("GITEA_BASE_URL", "https://git.xiaoxiajianji.com")
    repo = os.environ.get("GITEA_REPO", "xiaoxia/xiaoxia-saas")
    card["elements"].append(
        {
            "tag": "action",
            "actions": [
                {
                    "tag": "button",
                    "text": {"tag": "plain_text", "content": "查看CI面板"},
                    "type": "primary",
                    "url": f"{base_url}/{repo}/actions",
                }
            ],
        }
    )

    return {"msg_type": "interactive", "card": card}


def send_feishu(webhook: str, payload: dict) -> bool:
    """发送飞书webhook"""
    data = json.dumps(payload).encode()
    req = urllib.request.Request(
        webhook,
        data=data,
        headers={"Content-Type": "application/json"},
    )
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            result = json.loads(resp.read().decode())
            return result.get("code", -1) == 0 or result.get("StatusCode", -1) == 0
    except Exception as e:
        print(f"send feishu failed: {e}")
        return False


def main():
    parser = argparse.ArgumentParser(description="CI健康度每日巡检报告")
    parser.add_argument("--limit", type=int, default=30, help="统计最近N条run")
    parser.add_argument("--dry-run", action="store_true", help="只打印不发送")
    parser.add_argument("--always-notify", action="store_true", help="即使全部通过也发送通知")
    args = parser.parse_args()

    webhook = os.environ.get("CI_NOTIFY_WEBHOOK", "")
    if not webhook and not args.dry_run:
        print("未配置 CI_NOTIFY_WEBHOOK，跳过通知")
        # 还是执行健康检查输出到日志，方便排查
        data = run_health_check(args.limit)
        print(f"health check done: {len(data.get('failed_runs', []))} failed")
        return 0

    # 执行健康检查
    data = run_health_check(args.limit)
    failed_count = len(data.get("failed_runs", []))

    # 无失败且不强制通知 → 静默退出
    if failed_count == 0 and not args.always_notify:
        print("✅ 全部通过，静默退出")
        return 0

    # 构建并发送卡片
    card = build_feishu_card(data)

    if args.dry_run:
        print(json.dumps(card, ensure_ascii=False, indent=2))
        return 0

    success = send_feishu(webhook, card)
    if success:
        print(f"📤 已发送健康度报告，失败 {failed_count} 条")
    else:
        print("❌ 发送飞书通知失败")

    # 通知失败不阻断流程
    return 0


if __name__ == "__main__":
    sys.exit(main())
