"""统计项目代码行数,按后端/前端/测试分类"""

import os
from pathlib import Path

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

GROUPS: dict[str, dict[str, list[str]]] = {
    "后端": {
        "dirs": ["backend"],
        "exts": [".py"],
        "exclude": [],
    },
    "前端": {
        "dirs": ["frontend/src"],
        "exts": [".vue", ".js", ".css"],
        "exclude": [],
    },
    "测试": {
        "dirs": ["tests"],
        "exts": [".py"],
        "exclude": [],
    },
    "工具/配置": {
        "dirs": ["tools", "config", "constants"],
        "exts": [".py", ".toml", ".sh", ".json"],
        "exclude": ["code_spectra.db"],
    },
}


def display_width(s: str) -> int:
    """计算字符串的终端显示宽度(中文等全角字符占 2 列)"""
    w = 0
    for ch in s:
        if '\u4e00' <= ch <= '\u9fff' or '\u3000' <= ch <= '\u303f' or '\uff00' <= ch <= '\uffef':
            w += 2
        else:
            w += 1
    return w


def pad_str(s: str, width: int, align: str = "left") -> str:
    """按显示宽度填充字符串"""
    dw = display_width(s)
    pad = width - dw
    if align == "left":
        return s + " " * max(pad, 0)
    return " " * max(pad, 0) + s


def count_lines(path: Path) -> int:
    """统计单个文件的非空行数"""
    try:
        with open(path, encoding="utf-8", errors="ignore") as f:
            return sum(1 for line in f if line.strip())
    except Exception:
        return 0


def main() -> None:
    results: dict[str, dict] = {}
    grand_total = 0

    for group_name, cfg in GROUPS.items():
        total = 0
        files = 0
        for d in cfg["dirs"]:
            dir_path = PROJECT_ROOT / d
            if not dir_path.exists():
                continue
            for ext in cfg["exts"]:
                for fpath in dir_path.rglob(f"*{ext}"):
                    if fpath.name.startswith("."):
                        continue
                    # 跳过 __pycache__ 和 node_modules
                    if "__pycache__" in fpath.parts or "node_modules" in fpath.parts:
                        continue
                    lines = count_lines(fpath)
                    total += lines
                    files += 1

        results[group_name] = {"files": files, "lines": total}
        grand_total += total

    # 输出
    print(f"{pad_str('类别', 10)} {pad_str('文件数', 6, 'right')} {pad_str('行数', 8, 'right')}")
    print("-" * 26)
    total_files = sum(r['files'] for r in results.values())
    for group_name, stats in results.items():
        print(
            f"{pad_str(group_name, 10)} "
            f"{pad_str(str(stats['files']), 6, 'right')} "
            f"{pad_str(str(stats['lines']), 8, 'right')}"
        )
    print("-" * 26)
    print(
        f"{pad_str('合计', 10)} "
        f"{pad_str(str(total_files), 6, 'right')} "
        f"{pad_str(str(grand_total), 8, 'right')}"
    )


if __name__ == "__main__":
    main()