#!/usr/bin/env python3
"""
CI 状态查询模块 - 查询 run 列表、某分支/某 PR 的 CI 状态、失败详情

支持查询类型:
  - list_runs: 列出最近的 workflow runs
  - branch_status: 某分支最新 CI 状态
  - pr_status: 某 PR 的 CI 状态
  - failure_detail: 某次 run 的失败详情

用法:
  python3 scripts/ci/chatops/ci_query.py --branch develop
  python3 scripts/ci/chatops/ci_query.py --pr 123
  python3 scripts/ci/chatops/ci_query.py --run-id 456 --detail

设计:
  - 与飞书机器人 /ci status 命令对接
  - 返回结构化数据，上层负责格式化输出
"""

import argparse
import sys

from . import config
from .gitea_client import GiteaClient


class CIQuery:
    """CI 状态查询器"""

    def __init__(self, gitea_client=None):
        self.gitea = gitea_client or GiteaClient()

    # ── 查询方法 ──────────────────────────────────────

    def get_branch_status(self, branch, limit=5):
        """获取指定分支最新的 CI 状态

        Returns:
            dict: {branch, latest_run, recent_runs, overall_status}
        """
        runs, total = self.gitea.list_runs(branch=branch, limit=limit)
        if not runs:
            return {
                "branch": branch,
                "latest_run": None,
                "recent_runs": [],
                "overall_status": "no_runs",
                "total_count": total,
            }

        latest = runs[0]
        overall = self._derive_overall_status(runs)

        return {
            "branch": branch,
            "latest_run": latest,
            "recent_runs": runs,
            "overall_status": overall,
            "total_count": total,
        }

    def get_pr_status(self, pr_number):
        """获取指定 PR 的 CI 状态

        Returns:
            dict: {pr_number, pr_title, runs, overall_status}
        """
        pr = self.gitea.get_pr(pr_number)
        if not pr:
            return {
                "pr_number": pr_number,
                "pr_title": "未知",
                "runs": [],
                "overall_status": "pr_not_found",
            }

        pr_title = pr.get("title", "")
        runs = self.gitea.get_pr_ci_runs(pr_number, limit=10)
        overall = self._derive_overall_status(runs) if runs else "no_runs"

        return {
            "pr_number": pr_number,
            "pr_title": pr_title,
            "runs": runs,
            "overall_status": overall,
            "head_sha": pr.get("head", {}).get("sha", ""),
        }

    def get_failure_detail(self, run_id):
        """获取某次 run 的失败详情

        Returns:
            dict: {run_info, failed_jobs, summary}
        """
        run = self.gitea.get_run(run_id)
        if not run:
            return {"run_info": None, "failed_jobs": [], "summary": "Run not found"}

        failed_jobs = self.gitea.get_failed_jobs_summary(run_id, max_lines_per_job=30)

        summary_parts = []
        for job in failed_jobs:
            step = f"（步骤: {job['failed_step']}）" if job["failed_step"] else ""
            summary_parts.append(f"• {job['name']}{step}")

        summary = "\n".join(summary_parts) if summary_parts else "无失败 job（可能还在运行中）"

        return {
            "run_info": run,
            "failed_jobs": failed_jobs,
            "summary": summary,
            "total_jobs": len(self.gitea.get_run_jobs(run_id)),
        }

    def list_recent_runs(self, status=None, branch=None, limit=10):
        """列出最近的 runs"""
        runs, total = self.gitea.list_runs(status=status, branch=branch, limit=limit)
        return {"runs": runs, "total_count": total}

    # ── 辅助方法 ────────────────────────────────────

    @staticmethod
    def _derive_overall_status(runs):
        """根据最近 runs 推导整体状态

        Returns:
            success: 最近一次成功
            failing: 最近一次失败（连续失败）
            flaky: 有失败有成功（最近一次失败
            running: 有正在运行的
            unknown: 未知
        """
        if not runs:
            return "no_runs"

        # 检查是否有运行中的
        running = [r for r in runs if r.get("status") != "completed"]
        if running:
            return "running"

        # 看最近一次
        latest = runs[0]
        latest_conclusion = latest.get("conclusion", "unknown")

        if latest_conclusion == "success":
            return "success"

        if latest_conclusion == "failure":
            # 检查是否连续失败
            consecutive_failures = 0
            for r in runs:
                if r.get("conclusion") == "failure":
                    consecutive_failures += 1
                else:
                    break

            # 看之前有没有成功
            has_success = any(r.get("conclusion") == "success" for r in runs)

            if has_success:
                return "flaky"
            return "failing"

        return "unknown"

    # ── 格式化输出 ────────────────────────────────────

    @staticmethod
    def format_branch_status(status_data):
        """格式化分支状态为人类可读文本"""
        branch = status_data["branch"]
        latest = status_data["latest_run"]
        overall = status_data["overall_status"]

        status_emoji = {
            "success": "✅",
            "failing": "🔴",
            "flaky": "🟡",
            "running": "🔄",
            "no_runs": "⚪",
            "unknown": "❓",
        }.get(overall, "❓")

        lines = [f"**CI 状态：{branch} 分支**", f"整体状态: {status_emoji} {overall}"]

        if latest:
            name = latest.get("name", "Unknown")
            conclusion = latest.get("conclusion", latest.get("status", "unknown"))
            run_id = latest.get("id", "")
            created = latest.get("created_at", "")[:16].replace("T", " ")
            run_url = f"{config.GITEA_URL}/{config.GITEA_REPO}/actions/runs/{run_id}"
            lines.append(f"最新: [{name} #{run_id}]({run_url}) - {conclusion} ({created})")

        recent = status_data["recent_runs"]
        if len(recent) > 1:
            lines.append(f"\n最近 {len(recent)} 次:")
            for r in recent[:5]:
                c = r.get("conclusion", r.get("status", "?"))
                emoji = {"success": "✅", "failure": "❌", "skipped": "⏭️"}.get(c, "🔄")
                lines.append(f"  {emoji} #{r.get('id', '?')} {r.get('name', '?')[:30]} - {c}")

        return "\n".join(lines)

    @staticmethod
    def format_pr_status(status_data):
        """格式化 PR 状态为人类可读文本"""
        pr_num = status_data["pr_number"]
        pr_title = status_data["pr_title"]
        overall = status_data["overall_status"]

        status_emoji = {
            "success": "✅",
            "failing": "🔴",
            "flaky": "🟡",
            "running": "🔄",
            "no_runs": "⚪",
            "pr_not_found": "❓",
            "unknown": "❓",
        }.get(overall, "❓")

        pr_url = f"{config.GITEA_URL}/{config.GITEA_REPO}/pulls/{pr_num}"
        lines = [
            f"**CI 状态：PR #{pr_num}**",
            f"标题: [{pr_title}]({pr_url})",
            f"状态: {status_emoji} {overall}",
        ]

        runs = status_data["runs"]
        if runs:
            lines.append(f"\nCI Runs ({len(runs)}):")
            for r in runs[:5]:
                c = r.get("conclusion", r.get("status", "?"))
                emoji = {"success": "✅", "failure": "❌", "skipped": "⏭️"}.get(c, "🔄")
                run_id = r.get("id", "?")
                run_url = f"{config.GITEA_URL}/{config.GITEA_REPO}/actions/runs/{run_id}"
                lines.append(f"  {emoji} [{r.get('name', '?')[:30]} #{run_id}]({run_url}) - {c}")

        return "\n".join(lines)


# ── CLI 入口 ──────────────────────────────────────────


def main():
    parser = argparse.ArgumentParser(description="CI 状态查询")
    parser.add_argument("--branch", help="查询指定分支的 CI 状态")
    parser.add_argument("--pr", type=int, help="查询指定 PR 的 CI 状态")
    parser.add_argument("--run-id", help="查询指定 run 的详情")
    parser.add_argument("--detail", action="store_true", help="显示失败详情")
    parser.add_argument("--limit", type=int, default=5, help="返回数量限制")
    parser.add_argument("--status", help="按状态过滤: success/failure/running")

    args = parser.parse_args()

    query = CIQuery()

    if args.run_id:
        if args.detail:
            result = query.get_failure_detail(args.run_id)
            print(f"Run #{args.run_id} 失败详情:")
            print(result["summary"])
            if result["failed_jobs"]:
                print("\n详细日志尾部:")
                for job in result["failed_jobs"]:
                    print(f"\n--- {job['name']} ---")
                    print(job["log_tail"][:500] if job["log_tail"] else "无日志")
        else:
            run = query.gitea.get_run(args.run_id)
            if run:
                print(f"Run #{args.run_id}: {run.get('name')} - {run.get('conclusion', run.get('status'))}")
                print(f"分支: {run.get('head_branch', '?')}")
                print(f"触发: {run.get('event', '?')}")
            else:
                print(f"Run {args.run_id} 不存在")
    elif args.pr:
        result = query.get_pr_status(args.pr)
        print(CIQuery.format_pr_status(result))
    elif args.branch:
        result = query.get_branch_status(args.branch, limit=args.limit)
        print(CIQuery.format_branch_status(result))
    elif args.status:
        result = query.list_recent_runs(status=args.status, limit=args.limit)
        for r in result["runs"]:
            print(
                f"#{r.get('id')} {r.get('name')[:40]} - {r.get('conclusion', r.get('status'))} ({r.get('head_branch', '?')})"
            )
    else:
        parser.print_help()
        return 1

    return 0


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