#!/usr/bin/env python3
"""lint-workspace.py - workspace 구조 규칙 위반 감지 스크립트."""

import argparse
import os
import shutil
import time
from pathlib import Path
from typing import List, Tuple

Violation = Tuple[str, str]

# ---------------------------------------------------------------------------
# 허용 목록
# ---------------------------------------------------------------------------
ROOT_ALLOWED_FILES = {
    "CLAUDE.md", ".env", ".env.keys", ".gitignore", "pyproject.toml",
    "pyrightconfig.json", "requirements.txt", "conftest.py",
    ".pre-commit-config.yaml", "dispatch.py", "chain.py",
    "chain_manager.py", "orchestrator.py", "kickoff.py", "group_chat.py",
    "decision_logger.py", "cross_model_review.py", "report_parser.py",
    "sync-check.py", "inbox_utils.py", "glm-coder.py",
}

TEAM_ALLOWED_FILES = {
    "CLAUDE.md", "BOOTSTRAP.md", "IDENTITY.md", "HEARTBEAT.md",
    "TOOLS.md", "USER.md",
}

SCAN_DIRS = ["scripts", "workers", "teams"]


# ---------------------------------------------------------------------------
# 규칙별 검사 함수
# ---------------------------------------------------------------------------

def check_root_unwanted_files(workspace: Path) -> List[Violation]:
    """ERROR: workspace 루트에 불필요한 파일 존재."""
    violations: List[Violation] = []
    for item in workspace.iterdir():
        if item.is_file() and item.name not in ROOT_ALLOWED_FILES:
            violations.append(("ERROR", f"workspace 루트에 불필요한 파일: {item}"))
    return violations


def check_teams_scatter(workspace: Path) -> List[Violation]:
    """WARNING: teams/ 하위에 task-* 디렉토리 없이 파일 산재."""
    violations: List[Violation] = []
    teams_dir = workspace / "teams"
    if not teams_dir.exists():
        return violations
    for team_dir in teams_dir.iterdir():
        if not team_dir.is_dir():
            continue
        for item in team_dir.iterdir():
            if item.is_dir():
                continue  # 디렉토리는 허용 (qc/, task-* 포함)
            if item.name in TEAM_ALLOWED_FILES:
                continue
            violations.append((
                "WARNING",
                f"teams/{team_dir.name}에 태스크 격리 없는 파일: {item.name}",
            ))
    return violations


def check_tmp_old_files(workspace: Path) -> List[Violation]:
    """WARNING: tmp/에 7일 초과 파일."""
    violations: List[Violation] = []
    tmp_dir = workspace / "tmp"
    if not tmp_dir.exists():
        return violations
    cutoff = time.time() - 7 * 86400
    for item in tmp_dir.rglob("*"):
        if item.is_file() and item.stat().st_mtime < cutoff:
            violations.append(("WARNING", f"tmp/에 7일 초과 파일: {item}"))
    return violations


def check_long_py_files(workspace: Path) -> List[Violation]:
    """INFO: 200줄 초과 .py 파일 (scripts/, workers/, teams/ 하위)."""
    violations: List[Violation] = []
    for dirname in SCAN_DIRS:
        scan_dir = workspace / dirname
        if not scan_dir.exists():
            continue
        for py_file in scan_dir.rglob("*.py"):
            lines = len(py_file.read_text(errors="replace").splitlines())
            if lines > 200:
                violations.append(("INFO", f"200줄 초과: {py_file} ({lines}줄)"))
    return violations


def check_memory_events_done(workspace: Path) -> List[Violation]:
    """ERROR: memory/events/에 90일 초과 .done 파일."""
    violations: List[Violation] = []
    events_dir = workspace / "memory" / "events"
    if not events_dir.exists():
        return violations
    cutoff = time.time() - 90 * 86400
    for item in events_dir.iterdir():
        if item.is_file() and item.suffix == ".done" and item.stat().st_mtime < cutoff:
            violations.append(("ERROR", f"memory/events/에 90일 초과 .done 파일: {item}"))
    return violations


def check_disk_usage(workspace: Path) -> List[Violation]:
    """INFO: 디스크 사용량 요약."""
    usage = shutil.disk_usage(workspace)
    total_gb = usage.total / 1024 ** 3
    used_gb = usage.used / 1024 ** 3
    free_gb = usage.free / 1024 ** 3
    msg = f"디스크 사용량: {used_gb:.1f}GB / {total_gb:.1f}GB (여유: {free_gb:.1f}GB)"
    return [("INFO", msg)]


# ---------------------------------------------------------------------------
# 정렬 / 종료 코드
# ---------------------------------------------------------------------------

_ORDER = {"ERROR": 0, "WARNING": 1, "INFO": 2}


def sort_violations(violations: List[Violation]) -> List[Violation]:
    return sorted(violations, key=lambda v: _ORDER.get(v[0], 9))


def compute_exit_code(violations: List[Violation]) -> int:
    return 1 if any(sev == "ERROR" for sev, _ in violations) else 0


# ---------------------------------------------------------------------------
# main
# ---------------------------------------------------------------------------

def main() -> None:
    parser = argparse.ArgumentParser(description="workspace 구조 규칙 위반 감지")
    parser.add_argument(
        "--workspace",
        default=os.environ.get("WORKSPACE_ROOT", "/home/jay/workspace"),
        help="workspace 루트 경로 (기본값: $WORKSPACE_ROOT 또는 /home/jay/workspace)",
    )
    args = parser.parse_args()
    workspace = Path(args.workspace)

    all_violations: List[Violation] = []
    all_violations += check_root_unwanted_files(workspace)
    all_violations += check_teams_scatter(workspace)
    all_violations += check_tmp_old_files(workspace)
    all_violations += check_long_py_files(workspace)
    all_violations += check_memory_events_done(workspace)
    all_violations += check_disk_usage(workspace)

    sorted_v = sort_violations(all_violations)
    for sev, msg in sorted_v:
        print(f"[{sev}] {msg}")

    raise SystemExit(compute_exit_code(sorted_v))


if __name__ == "__main__":
    main()
