#!/usr/bin/env python3
"""
pre-commit-check.py · 冰朔小说创作系统 · 提交前自动检查

放在 scripts/ 目录，git commit 前手动或通过 pre-commit hook 自动调用。
检查范围：chapters/ 下所有 .txt 文件（正文）。

检查项：
1. 字数：非空白字符 2000-2800 区间（仅单章文件）
2. 违禁词：AI 化套话
3. 半角标点：引号、省略号、破折号
4. 代词一致性：许怀钰=他，何采霏=她（按书检测）
5. Markdown 泄露：** ## 等
6. 元叙述：正文中不出现"第X章"（标题行除外，多章文件跳过）

用法：
  python3 scripts/pre-commit-check.py

退出码：
  0 = 全部通过
  1 = 有不达标项
"""

import re
import os
import sys
import glob

REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CHAPTERS_DIR = os.path.join(REPO_ROOT, "chapters")

# --- 检查规则 ---

# 违禁词：AI 化套话
# 注意："最后"单独检查，只匹配段首/句首的"最后，"模式（AI 三段式标志）
FORBIDDEN_WORDS = [
    "值得注意的是", "不得不说", "总的来说",
    "作为一个", "说道",
    "心中充满", "不禁", "不由得",
    "与此同时",
]

# "最后"只检查句首用法（AI 三段式 "最后，"）
FORBIDDEN_PATTERNS = [
    (r'\n\s*最后[，。]', '"最后"句首（AI 三段式）'),
]

HALF_WIDTH_CHECKS = [
    ('"', "半角引号（应使用中文双引号）"),
    ("...", "半角省略号（应使用……6点）"),
    ("--", "半角破折号（应使用——中文破折号）"),
]

MARKDOWN_LEAKS = ["**", "##"]

# 每本书的主角代词规则：主角名 -> 正确代词
PROTAGONIST_RULES = {
    "许怀钰": "他",
    "何采霏": "她",
}

def count_chars(text):
    """非空白字符统计（D169 铁律）"""
    return len(re.findall(r'[^\s]', text))

def is_multi_chapter_file(filename):
    """判断是否为多章合并文件（之之侧旧格式）"""
    # 匹配 "肖轩447-450章" / "沈婉凝278-282章" / "女频续写263章" 等
    if re.search(r'\d+-\d+章', filename):
        return True
    # 匹配 "肖轩447-450章【8684字】" 这种
    if '【' in filename and '章' in filename:
        return True
    # 匹配 "女频续写263章（沈婉凝）" 这种单文件多章
    if re.search(r'\d+章.*（', filename) and '第' not in filename:
        return True
    return False

def check_chapter(filepath):
    """检查单个章节文件，返回 (passed, issues, skipped_reason)"""
    issues = []
    skipped_reason = None
    
    with open(filepath, 'r', encoding='utf-8') as f:
        text = f.read()
    
    filename = os.path.basename(filepath)
    
    # 0. 空文件检查
    if not text.strip():
        issues.append(f"  ❌ 空文件")
        return False, issues, None
    
    # 判断是否为多章合并文件
    multi_chapter = is_multi_chapter_file(filename)
    if multi_chapter:
        skipped_reason = "多章合并文件（旧格式，跳过字数和元叙述检查）"
    
    # 1. 字数检查（仅单章文件）
    char_count = count_chars(text)
    if not multi_chapter:
        if char_count < 2000:
            issues.append(f"  ❌ 字数不足: {char_count} < 2000（差 {2000 - char_count} 字）")
        elif char_count > 2800:
            issues.append(f"  ⚠️ 字数超标: {char_count} > 2800")
        else:
            issues.append(f"  ✓ 字数: {char_count}")
    else:
        issues.append(f"  ℹ️ 字数: {char_count}（多章合并，不判定）")
    
    # 2. 违禁词检查（所有文件都查）
    for word in FORBIDDEN_WORDS:
        if word in text:
            count = text.count(word)
            issues.append(f"  ❌ 违禁词 \"{word}\": {count} 次")
    
    # 2b. 违禁模式检查（句首"最后"等）
    for pattern, desc in FORBIDDEN_PATTERNS:
        matches = re.findall(pattern, text)
        if matches:
            issues.append(f"  ❌ {desc}: {len(matches)} 处")
    
    # 3. 半角标点检查（所有文件都查）
    for pattern_str, desc in HALF_WIDTH_CHECKS:
        if pattern_str in text:
            count = text.count(pattern_str)
            issues.append(f"  ⚠️ {desc}: {count} 处")
    
    # 4. Markdown 泄露（所有文件都查）
    for md in MARKDOWN_LEAKS:
        if md in text:
            issues.append(f"  ❌ Markdown 泄露: \"{md}\"")
    
    # 5. 元叙述检查（仅单章文件）
    if not multi_chapter:
        lines = text.split('\n')
        for i, line in enumerate(lines):
            if i == 0:  # 标题行，跳过
                continue
            if re.search(r'第\s*\d+\s*章', line):
                issues.append(f"  ❌ 元叙述: 第{i+1}行出现\"第X章\"")
    
    # 6. 代词一致性
    dirname = os.path.basename(os.path.dirname(filepath))
    for name, correct_pronoun in PROTAGONIST_RULES.items():
        if name in dirname or name in filename:
            wrong_pronoun = "她" if correct_pronoun == "他" else "他"
            wrong_pattern = f"{name}{wrong_pronoun}"
            if wrong_pattern in text:
                issues.append(f"  ❌ 代词错误: \"{wrong_pattern}\"（{name}应为{correct_pronoun}）")
    
    # 判断是否通过
    # ⚠️ 标记为警告（不阻断提交），❌ 标记为错误（阻断提交）
    has_errors = any("❌" in issue for issue in issues)
    passed = not has_errors
    return passed, issues, skipped_reason

def main():
    print("=" * 60)
    print("冰朔小说创作系统 · 提交前自动检查")
    print("=" * 60)
    print()
    
    # 找到所有 .txt 文件
    txt_files = glob.glob(os.path.join(CHAPTERS_DIR, "**", "*.txt"), recursive=True)
    
    if not txt_files:
        print("未找到章节文件，跳过检查。")
        sys.exit(0)
    
    all_passed = True
    total_files = 0
    failed_files = 0
    skipped_files = 0
    
    for filepath in sorted(txt_files):
        rel_path = os.path.relpath(filepath, REPO_ROOT)
        total_files += 1
        
        passed, issues, skipped_reason = check_chapter(filepath)
        
        if skipped_reason:
            skipped_files += 1
        
        if not passed:
            all_passed = False
            failed_files += 1
            print(f"📋 {rel_path}")
            if skipped_reason:
                print(f"  ℹ️ {skipped_reason}")
            for issue in issues:
                print(issue)
            print()
    
    # 汇总
    print("=" * 60)
    print(f"检查完成: {total_files} 个文件, {total_files - failed_files} 通过, {failed_files} 不达标, {skipped_files} 跳过")
    
    if all_passed:
        print("✅ 全部通过，可以提交。")
        sys.exit(0)
    else:
        print("❌ 有不达标项（❌ 为阻断项，⚠️ 为提醒项）。")
        print("   阻断项请修复后再提交。")
        sys.exit(1)

if __name__ == "__main__":
    main()
