"""环节钩子：PlantUML 与 CHANGELOG 校验。"""

from __future__ import annotations

import shutil
import subprocess
from pathlib import Path
from typing import Any

from aide.core import output
from aide.flow.errors import FlowError
from aide.flow.git import GitIntegration
from aide.flow.types import FlowStatus


def run_pre_commit_hooks(
    *,
    root: Path,
    git: GitIntegration,
    status: FlowStatus | None,
    from_phase: str | None,
    to_phase: str,
    action: str,
    config: dict[str, Any] | None = None,
) -> None:
    if from_phase == "flow-design" and action in {"next-part", "back-part"}:
        _hook_plantuml(root=root, config=config)
    if from_phase == "docs" and action in {"next-part", "back-part"}:
        _hook_changelog_on_leave_docs(root=root, git=git, status=status)


def run_post_commit_hooks(*, to_phase: str, action: str) -> None:
    if to_phase == "docs" and action in {"start", "next-part", "back-part"}:
        output.info("请更新 CHANGELOG.md")


def _get_plantuml_command(config: dict[str, Any] | None) -> list[str] | None:
    """获取 PlantUML 命令，优先使用配置的 jar 文件。"""
    if config:
        jar_path = config.get("plantuml", {}).get("jar_path")
        java_path = config.get("plantuml", {}).get("java_path", "java")

        if jar_path:
            # 尝试解析 jar 路径
            jar_file = Path(jar_path)
            if not jar_file.is_absolute():
                # 相对路径，相对于 aide-program 目录
                aide_program_dir = Path(__file__).parent.parent.parent
                jar_file = aide_program_dir / jar_path

            if jar_file.exists():
                return [java_path, "-jar", str(jar_file)]

    # 回退到系统 plantuml 命令
    if shutil.which("plantuml"):
        return ["plantuml"]

    return None


def _hook_plantuml(*, root: Path, config: dict[str, Any] | None = None) -> None:
    """PlantUML 校验和构建钩子。"""
    # 获取流程图目录
    diagram_path = ".aide/diagrams"
    if config:
        diagram_path = config.get("flow", {}).get("diagram_path", diagram_path)

    diagram_dir = root / diagram_path

    # 收集所有 .puml 文件
    candidates: list[Path] = []

    # 从配置的流程图目录
    if diagram_dir.exists():
        candidates.extend([p for p in diagram_dir.rglob("*.puml") if p.is_file()])
        candidates.extend([p for p in diagram_dir.rglob("*.plantuml") if p.is_file()])

    # 也检查 docs 和 discuss 目录（向后兼容）
    for base in (root / "docs", root / "discuss"):
        if not base.exists():
            continue
        candidates.extend([p for p in base.rglob("*.puml") if p.is_file()])
        candidates.extend([p for p in base.rglob("*.plantuml") if p.is_file()])

    if not candidates:
        return

    # 获取 PlantUML 命令
    plantuml_cmd = _get_plantuml_command(config)
    if plantuml_cmd is None:
        output.warn("未找到 PlantUML（jar 或系统命令），已跳过校验/PNG 生成")
        return

    # 先校验所有文件
    errors: list[str] = []
    for file_path in candidates:
        result = subprocess.run(
            plantuml_cmd + ["-checkonly", str(file_path)],
            cwd=root,
            text=True,
            capture_output=True,
        )
        if result.returncode != 0:
            detail = (result.stderr or "").strip() or (result.stdout or "").strip()
            errors.append(f"{file_path.name}: {detail}")

    if errors:
        error_msg = "\n".join(errors)
        raise FlowError(f"PlantUML 语法校验失败:\n{error_msg}")

    # 校验通过，生成 PNG
    for file_path in candidates:
        result = subprocess.run(
            plantuml_cmd + ["-tpng", str(file_path)],
            cwd=root,
            text=True,
            capture_output=True,
        )
        if result.returncode != 0:
            detail = (result.stderr or "").strip() or (result.stdout or "").strip()
            raise FlowError(f"PlantUML PNG 生成失败: {file_path} {detail}".strip())

    output.ok(f"PlantUML 处理完成: {len(candidates)} 个文件")


def _hook_changelog_on_leave_docs(*, root: Path, git: GitIntegration, status: FlowStatus | None) -> None:
    changelog = root / "CHANGELOG.md"
    if not changelog.exists():
        raise FlowError("离开 docs 前需要更新 CHANGELOG.md（当前文件不存在）")

    git.ensure_repo()
    if git.status_porcelain("CHANGELOG.md").strip():
        return

    if status is None:
        raise FlowError("离开 docs 前需要更新 CHANGELOG.md（未找到流程状态）")

    for entry in status.history:
        if entry.phase != "docs":
            continue
        if not entry.git_commit:
            continue
        if git.commit_touches_path(entry.git_commit, "CHANGELOG.md"):
            return

    raise FlowError("离开 docs 前需要更新 CHANGELOG.md（未检测到 docs 阶段的更新记录）")

