import argparse
import subprocess
import sys
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parent.parent

WORKFLOW_TRIGGER_PATHS = {
    "AGENTS.md",
    "README.md",
    "操作手册.md",
    "scripts/case_pipeline.py",
    "scripts/export_excel.py",
    "scripts/governance_audit.py",
    "knowledge_base/01_standards/test_case_template.md",
    "knowledge_base/01_standards/definition_of_done.md",
    "knowledge_base/01_standards/review_checklist.md",
    "knowledge_base/01_standards/terminology.md",
    "knowledge_base/01_standards/terminology_optional_saas.md",
}
WORKFLOW_TRIGGER_PREFIXES = (
    ".claude/",
    "agents/",
    "scripts/",
    "knowledge_base/01_standards/",
)
STRUCTURE_TRIGGER_PREFIXES = (
    ".claude/",
    "agents/",
    "scripts/",
    "knowledge_base/01_standards/",
)
IGNORED_PREFIXES = (
    "output/",
    "requirements/",
    "knowledge_base/02_history/",
    "knowledge_base/03_best_practices/",
)

CONSISTENCY_EXPECTATIONS = {
    "AGENTS.md": [
        "fleet_runner.py",
        "case_pipeline.py",
        "output/manifests/{BASE_NAME}.json",
        "knowledge_base/00_project/project_profile.md",
        "knowledge_base/01_standards/review_checklist.md",
        "normalized_requirement_file",
    ],
    ".claude/commands/case_generate.md": [
        "fleet_runner.py",
        "qe-fleet run",
        "case_generate",
        "output/manifests/{BASE_NAME}.json",
    ],
    ".claude/skills/case_generate/SKILL.md": [
        "fleet_runner.py",
        "qe-fleet run",
        "case_generate",
        "output/manifests/{BASE_NAME}.json",
    ],
    ".claude/instructions.md": [
        "scripts/case_pipeline.py",
        "effective_terminology_files",
        "knowledge_base/00_project/project_profile.md",
        "knowledge_base/01_standards/review_checklist.md",
        "normalized_requirement_file",
    ],
    "README.md": [
        "output/manifests/{BASE_NAME}.json",
        "术语文件按需求内容自动识别生效范围",
        "knowledge_base/00_project/project_profile.md",
        "review_checklist.md",
        "source_docs/requirements_raw",
        "output/versions/{BASE_NAME}/v1/",
        "VERSION_INDEX.md",
        "最近 `3` 个版本",
    ],
    "操作手册.md": [
        "terminology_optional_saas.md",
        "自动识别",
        "project_profile.md",
        "review_checklist.md",
        "source_docs/",
        "output/versions/{BASE_NAME}/v1/",
        "snapshot_meta.json",
        "最近 `3` 个版本",
    ],
}


def read_text(relative_path: str) -> str:
    return (REPO_ROOT / relative_path).read_text(encoding="utf-8")


def git_status_paths() -> list[tuple[str, str]]:
    try:
        result = subprocess.run(
            ["git", "status", "--porcelain"],
            cwd=REPO_ROOT,
            check=True,
            capture_output=True,
            text=True,
        )
    except subprocess.CalledProcessError as exc:
        raise RuntimeError(exc.stderr.strip() or "无法读取 git status。") from exc

    items: list[tuple[str, str]] = []
    for raw_line in result.stdout.splitlines():
        if not raw_line:
            continue
        status = raw_line[:2]
        payload = raw_line[3:]
        path = payload.split(" -> ")[-1].strip()
        if path:
            items.append((status, path))
    return items


def matches_any_prefix(path: str, prefixes: tuple[str, ...]) -> bool:
    return any(path.startswith(prefix) for prefix in prefixes)


def should_ignore(path: str) -> bool:
    return matches_any_prefix(path, IGNORED_PREFIXES)


def is_workflow_trigger(path: str) -> bool:
    return path in WORKFLOW_TRIGGER_PATHS or matches_any_prefix(path, WORKFLOW_TRIGGER_PREFIXES)


def is_structure_trigger(path: str, status: str) -> bool:
    if "?" in status or "A" in status or "D" in status or "R" in status:
        return matches_any_prefix(path, STRUCTURE_TRIGGER_PREFIXES)
    return False


def classify_changed_files(items: list[tuple[str, str]]) -> dict[str, list[str]]:
    workflow_hits: list[str] = []
    structure_hits: list[str] = []
    ignored_hits: list[str] = []

    for status, path in items:
        if should_ignore(path):
            ignored_hits.append(path)
            continue
        if is_workflow_trigger(path):
            workflow_hits.append(path)
        if is_structure_trigger(path, status):
            structure_hits.append(path)

    return {
        "workflow_hits": sorted(set(workflow_hits)),
        "structure_hits": sorted(set(structure_hits)),
        "ignored_hits": sorted(set(ignored_hits)),
    }


def audit_consistency() -> list[str]:
    issues: list[str] = []

    for relative_path, snippets in CONSISTENCY_EXPECTATIONS.items():
        content = read_text(relative_path)
        for snippet in snippets:
            if snippet not in content:
                issues.append(f"{relative_path} 缺少关键片段: {snippet}")

    return issues


def print_trigger_report(classification: dict[str, list[str]]) -> bool:
    workflow_hits = classification["workflow_hits"]
    structure_hits = classification["structure_hits"]
    should_run = bool(workflow_hits or structure_hits)

    print(f"should_run={str(should_run).lower()}")
    if workflow_hits:
        print("workflow_hits:")
        for path in workflow_hits:
            print(f"  - {path}")
    if structure_hits:
        print("structure_hits:")
        for path in structure_hits:
            print(f"  - {path}")
    return should_run


def command_should_run() -> int:
    classification = classify_changed_files(git_status_paths())
    should_run = print_trigger_report(classification)
    return 0 if should_run else 1


def command_audit() -> int:
    issues = audit_consistency()
    if issues:
        print("audit_status=fail")
        for issue in issues:
            print(f"- {issue}")
        return 1

    print("audit_status=pass")
    return 0


def command_auto() -> int:
    classification = classify_changed_files(git_status_paths())
    should_run = print_trigger_report(classification)
    if not should_run:
        print("audit_skipped=true")
        return 0

    issues = audit_consistency()
    if issues:
        print("audit_status=fail")
        for issue in issues:
            print(f"- {issue}")
        return 1

    print("audit_status=pass")
    return 0


def main() -> int:
    parser = argparse.ArgumentParser(description="流程一致性与文档滞后审计。")
    subparsers = parser.add_subparsers(dest="command", required=True)

    subparsers.add_parser("should-run", help="根据当前 git 变更判断是否需要触发治理审计。")
    subparsers.add_parser("audit", help="执行一致性与文档滞后检查。")
    subparsers.add_parser("auto", help="自动判断是否触发，并在需要时执行审计。")

    args = parser.parse_args()

    if args.command == "should-run":
        return command_should_run()
    if args.command == "audit":
        return command_audit()
    if args.command == "auto":
        return command_auto()
    return 1


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