#!/usr/bin/env python3
"""
课评出勤数据生成器
扫描 .claude/memory/class/ 下的所有 feedback 文件，生成出勤 JSON 数据。
支持：
  - 正常课评文件 → present
  - (请假) 标记文件 → leave
  - _补课 标记文件 → present（补课标注）
  - 补课/ 目录下的文件 → present（补课标注）

用法：
  python src/generate_attendance.py

输出：
  .claude/memory/config/attendance_data.js  （JS 变量文件，供 HTML 加载）
  .claude/memory/config/attendance_data.json （纯 JSON 数据文件）
"""

import json
import os
import re
from datetime import datetime, timedelta

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CLASS_DIR = os.path.join(BASE_DIR, '.claude', 'memory', 'class')
OUTPUT_JS = os.path.join(BASE_DIR, '.claude', 'memory', 'config', 'attendance_data.js')
OUTPUT_JSON = os.path.join(BASE_DIR, '.claude', 'memory', 'config', 'attendance_data.json')

SEMESTER_START = datetime(2026, 3, 2)  # 学期开始日期（周一）


def date_to_week(date_str):
    """将 YYYYMMDD 格式的日期转换为学期周数"""
    try:
        dt = datetime.strptime(date_str, '%Y%m%d')
        diff = (dt - SEMESTER_START).days
        if diff < 0:
            return None
        week = diff // 7 + 1
        return week
    except ValueError:
        return None


def parse_feedback_filename(filename):
    """解析 feedback 文件名，返回 (date_str, status, is_makeup)

    >>> parse_feedback_filename('20260606_DISC-014.md')
    ('20260606', 'present', False)
    >>> parse_feedback_filename('20260509_DISC-010(请假).md')
    ('20260509', 'leave', False)
    >>> parse_feedback_filename('20260505_DISC-009_补课.md')
    ('20260505', 'present', True)
    """
    # 匹配: YYYYMMDD_anything.md
    # 先去掉 .md 后缀
    basename = filename[:-3] if filename.endswith('.md') else filename

    # 提取前 8 位日期
    date_match = re.match(r'(\d{8})', basename)
    if not date_match:
        return None, None, False

    date_str = date_match.group(1)

    # 判断是否为请假
    is_leave = '(请假)' in basename
    is_makeup = '_补课' in basename

    status = 'leave' if is_leave else 'present'

    return date_str, status, is_makeup


def scan_class_dirs():
    """扫描所有班级目录，返回出勤数据字典"""
    attendance = {}

    if not os.path.isdir(CLASS_DIR):
        print(f"⚠️  找不到班级目录: {CLASS_DIR}")
        return attendance

    for class_name in sorted(os.listdir(CLASS_DIR)):
        class_path = os.path.join(CLASS_DIR, class_name)
        if not os.path.isdir(class_path):
            continue

        # 跳过 summaries 等非学生目录
        class_attendance = {}

        # 扫描学生目录（包括补课/ 目录）
        for item in sorted(os.listdir(class_path)):
            item_path = os.path.join(class_path, item)
            if not os.path.isdir(item_path):
                continue

            # 跳过非学生目录
            if item in ('summaries', '.backup', '.tmp'):
                continue

            if item == '补课':
                # 扫描补课目录下的学生
                for makeup_student in sorted(os.listdir(item_path)):
                    makeup_path = os.path.join(item_path, makeup_student)
                    if not os.path.isdir(makeup_path):
                        continue
                    scan_student_feedback(makeup_path, class_attendance, makeup_student, is_makeup=True)
            else:
                # 普通学生目录
                scan_student_feedback(item_path, class_attendance, item, is_makeup=False)

        if class_attendance:
            attendance[class_name] = class_attendance

    return attendance


def scan_student_feedback(student_path, class_attendance, student_name, is_makeup=False):
    """扫描单个学生的 feedback 目录"""
    feedback_dir = os.path.join(student_path, 'feedback')
    if not os.path.isdir(feedback_dir):
        return

    student_records = {}

    for filename in sorted(os.listdir(feedback_dir)):
        if not filename.endswith('.md'):
            continue

        date_str, status, file_is_makeup = parse_feedback_filename(filename)
        if not date_str or not status:
            continue

        week = date_to_week(date_str)
        if week is None:
            print(f"  ⚠️  跳过无法解析周数的文件: {filename}")
            continue

        # 补课标记: 记录为 present，但添加标记
        student_records[str(week)] = status

    if student_records:
        class_attendance[student_name] = student_records


def format_as_js(attendance_data):
    """将出勤数据格式化为 JS 变量定义"""
    json_str = json.dumps(attendance_data, ensure_ascii=False, indent=2)
    return f"""// ===============================================
// 课评出勤数据（自动生成）
// 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
// 来源: .claude/memory/class/*/feedback/
// ===============================================
// 运行 python src/generate_attendance.py 重新生成

const ATTENDANCE_DATA = {json_str};
"""


def main():
    print("[Scanning] Class dir: " + CLASS_DIR)
    attendance_data = scan_class_dirs()

    # 统计
    total_classes = len(attendance_data)
    total_students = sum(len(students) for students in attendance_data.values())
    total_records = sum(
        sum(len(weeks) for weeks in students.values())
        for students in attendance_data.values()
    )

    print("[Done] Classes: %d, Students: %d, Records: %d" % (total_classes, total_students, total_records))

    # 写入 JS 文件
    os.makedirs(os.path.dirname(OUTPUT_JS), exist_ok=True)
    with open(OUTPUT_JS, 'w', encoding='utf-8') as f:
        f.write(format_as_js(attendance_data))
    print("[OK] JS: " + OUTPUT_JS)

    # 写入 JSON 文件
    with open(OUTPUT_JSON, 'w', encoding='utf-8') as f:
        json.dump(attendance_data, f, ensure_ascii=False, indent=2)
    print("[OK] JSON: " + OUTPUT_JSON)


if __name__ == '__main__':
    main()
