#!/usr/bin/env python3
"""
sync_verifiers.py - 팀 간 verifier 파일 동기화 검사 스크립트

모든 팀(dev1, dev4, dev5, dev6, dev7)의 qc/verifiers/ 디렉토리에 있는
공유 verifier 파일을 비교하고, 차이가 있으면 보고합니다.
--fix 옵션으로 정본(canonical) 파일을 다른 팀에 자동 복사할 수 있습니다.
"""

import argparse
import difflib
import os
import shutil
import sys

VERIFIERS_SUBDIR = "qc/verifiers"


def get_workspace_root() -> str:
    """이 스크립트 기준으로 teams/ 디렉토리를 찾습니다."""
    script_dir = os.path.dirname(os.path.abspath(__file__))
    # shared/ -> teams/
    return os.path.dirname(script_dir)


def _discover_teams() -> list[str]:
    """teams/ 하위에서 qc/verifiers 디렉토리가 존재하는 팀 자동 발견."""
    teams_dir = get_workspace_root()
    _workspace_root = os.path.dirname(teams_dir)
    try:
        if _workspace_root not in sys.path:
            sys.path.insert(0, _workspace_root)
        from utils.org_loader import get_dev_short_ids  # pyright: ignore[reportMissingImports]

        candidates = get_dev_short_ids()
    except ImportError:
        candidates = ["dev1", "dev2", "dev3", "dev4", "dev5", "dev6", "dev7", "dev8"]

    found: list[str] = []
    for team in candidates:
        verifiers_path = os.path.join(teams_dir, team, VERIFIERS_SUBDIR)
        if os.path.isdir(verifiers_path):
            found.append(team)
    return found


TEAMS = _discover_teams()


def get_verifiers_dir(workspace_root: str, team: str) -> str:
    return os.path.join(workspace_root, team, VERIFIERS_SUBDIR)


def collect_py_files(verifiers_dir: str) -> list[str]:
    """
    verifiers_dir에서 __init__.py를 제외하고
    tests/ 서브디렉토리를 제외한 .py 파일 목록을 반환합니다.
    """
    files: list[str] = []
    if not os.path.isdir(verifiers_dir):
        return files
    for entry in os.scandir(verifiers_dir):
        if entry.is_file() and entry.name.endswith(".py") and entry.name != "__init__.py":
            files.append(entry.name)
    return sorted(files)


def read_file(path: str) -> str | None:
    """파일을 읽어 내용을 반환합니다. 읽기 실패 시 None을 반환합니다."""
    try:
        with open(path, encoding="utf-8") as f:
            return f.read()
    except OSError:
        return None


def compare_files(
    canonical_team: str,
    other_teams: list[str],
    workspace_root: str,
    target_file: str | None = None,
) -> dict[str, dict[str, str | None]]:
    """
    canonical_team의 파일과 other_teams의 파일을 비교합니다.

    Returns:
        {
            filename: {
                team: diff_text | None  # None이면 동일
            }
        }
    """
    canonical_dir = get_verifiers_dir(workspace_root, canonical_team)
    canonical_files = collect_py_files(canonical_dir)

    if target_file is not None:
        if target_file in canonical_files:
            canonical_files = [target_file]
        else:
            print(
                f"[ERROR] '{target_file}' 파일이 {canonical_team} verifiers 디렉토리에 없습니다.",
                file=sys.stderr,
            )
            sys.exit(1)

    results: dict[str, dict[str, str | None]] = {}

    for filename in canonical_files:
        canonical_path = os.path.join(canonical_dir, filename)
        canonical_content = read_file(canonical_path)

        if canonical_content is None:
            print(
                f"[WARN] 정본 파일을 읽을 수 없습니다: {canonical_path}",
                file=sys.stderr,
            )
            continue

        file_diffs: dict[str, str | None] = {}
        for team in other_teams:
            team_dir = get_verifiers_dir(workspace_root, team)
            team_path = os.path.join(team_dir, filename)
            team_content = read_file(team_path)

            if team_content is None:
                file_diffs[team] = f"[파일 없음] {team_path}"
                continue

            if canonical_content == team_content:
                file_diffs[team] = None
            else:
                diff = difflib.unified_diff(
                    canonical_content.splitlines(keepends=True),
                    team_content.splitlines(keepends=True),
                    fromfile=f"{canonical_team}/{VERIFIERS_SUBDIR}/{filename}",
                    tofile=f"{team}/{VERIFIERS_SUBDIR}/{filename}",
                )
                file_diffs[team] = "".join(diff)

        results[filename] = file_diffs

    return results


def fix_files(
    canonical_team: str,
    workspace_root: str,
    diffs: dict[str, dict[str, str | None]],
) -> None:
    """차이가 있는 파일을 정본으로 덮어씁니다."""
    canonical_dir = get_verifiers_dir(workspace_root, canonical_team)
    fixed_count = 0
    for filename, team_diffs in diffs.items():
        canonical_path = os.path.join(canonical_dir, filename)
        for team, diff_text in team_diffs.items():
            if diff_text is None:
                continue
            team_dir = get_verifiers_dir(workspace_root, team)
            team_path = os.path.join(team_dir, filename)
            try:
                shutil.copy2(canonical_path, team_path)
                print(f"  [FIX] {canonical_team} -> {team} : {filename}")
                fixed_count += 1
            except OSError as e:
                print(f"  [ERROR] 복사 실패 {canonical_path} -> {team_path}: {e}", file=sys.stderr)
    if fixed_count == 0:
        print("  수정할 파일이 없습니다.")
    else:
        print(f"\n  총 {fixed_count}개 파일을 수정했습니다.")


def main() -> None:
    parser = argparse.ArgumentParser(
        description="팀 간 verifier 파일 동기화 검사 및 수정 도구",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
예시:
  python3 sync_verifiers.py                        # dev1 기준으로 전체 비교
  python3 sync_verifiers.py --canonical dev5       # dev5 기준으로 전체 비교
  python3 sync_verifiers.py --file pyright_check.py  # 특정 파일만 비교
  python3 sync_verifiers.py --fix                  # 차이 파일을 정본으로 덮어쓰기
  python3 sync_verifiers.py --canonical dev5 --fix # dev5 기준으로 수정
""",
    )
    parser.add_argument(
        "--canonical",
        default="dev1",
        choices=TEAMS,
        metavar="TEAM",
        help=f"정본으로 사용할 팀 (기본: dev1, 선택: {', '.join(TEAMS)})",
    )
    parser.add_argument(
        "--file",
        default=None,
        metavar="FILENAME",
        help="비교할 특정 파일 이름 (예: pyright_check.py)",
    )
    parser.add_argument(
        "--fix",
        action="store_true",
        help="차이가 있는 파일을 정본으로 덮어쓰기",
    )
    args = parser.parse_args()

    workspace_root = get_workspace_root()
    canonical_team: str = args.canonical
    other_teams = [t for t in TEAMS if t != canonical_team]

    print(f"정본 팀: {canonical_team}")
    print(f"비교 팀: {', '.join(other_teams)}")
    print(f"작업 공간: {workspace_root}")
    if args.file:
        print(f"비교 대상 파일: {args.file}")
    print()

    diffs = compare_files(canonical_team, other_teams, workspace_root, target_file=args.file)

    has_diff = False
    for filename, team_diffs in diffs.items():
        diff_teams = {team: d for team, d in team_diffs.items() if d is not None}
        same_teams = [team for team, d in team_diffs.items() if d is None]

        if diff_teams:
            has_diff = True
            print(f"[DIFF] {filename}")
            if same_teams:
                print(f"  동일: {', '.join(same_teams)}")
            for team, diff_text in diff_teams.items():
                print(f"  차이: {team}")
                if diff_text and not diff_text.startswith("[파일 없음]"):
                    for line in diff_text.splitlines():
                        print(f"    {line}")
                else:
                    print(f"    {diff_text}")
            print()
        else:
            print(f"[OK]   {filename}  (모든 팀 동일)")

    print()
    if has_diff:
        print("결과: 차이가 있는 파일이 존재합니다.")
        if args.fix:
            print("\n--fix 모드: 정본으로 덮어씁니다...")
            fix_files(canonical_team, workspace_root, diffs)
        else:
            print("  --fix 옵션을 사용하면 자동으로 정본으로 덮어씁니다.")
        sys.exit(1)
    else:
        print("결과: 모든 팀의 verifier 파일이 정본과 동일합니다.")
        sys.exit(0)


if __name__ == "__main__":
    main()
