#!/usr/bin/env python3
"""
简化版OJ学生做题数据查询脚本

使用方式:
    python scripts/get_student_oj.py --homework-id <作业ID> --student <学生姓名>

功能:
    1. 登录OJ系统
    2. 通过homework ID获取题目列表
    3. 获取提交记录并解析学生做题情况
    4. 输出Markdown格式的OJ数据
"""

import io
import re
import sys
from html import unescape
from pathlib import Path

# 修复Windows控制台编码
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')

import httpx


def load_env():
    """从.env文件加载配置"""
    env_path = Path(__file__).parent.parent / '.env'
    env = {}
    if env_path.exists():
        for line in env_path.read_text(encoding='utf-8').split('\n'):
            line = line.strip()
            if line and not line.startswith('#') and '=' in line:
                key, value = line.split('=', 1)
                env[key] = value
    return env


def strip_tags(html: str) -> str:
    """移除HTML标签"""
    text = re.sub(r"<[^>]+>", "", html)
    return unescape(text).replace("\xa0", " ").strip()


def detect_status(row_html: str) -> str:
    """识别判题状态"""
    status_map = {
        "Accepted": "AC",
        "Wrong Answer": "WA",
        "Compile Error": "CE",
        "Time Limit Exceeded": "TLE",
        "Runtime Error": "RE",
        "Presentation Error": "PE",
    }
    for keyword, status in status_map.items():
        if keyword in row_html:
            return status
    return "UNKNOWN"


def get_student_oj_data(homework_id: str, student_name: str) -> str:
    """
    获取指定学生在指定作业中的OJ做题数据

    Args:
        homework_id: 作业ID（如 6a2bbd65aeff4da880b8f01d）
        student_name: 学生姓名

    Returns:
        Markdown格式的OJ数据
    """
    env = load_env()
    base_url = env.get('OJ_BASE_URL', 'https://oj.qonnwolf.com')
    username = env.get('OJ_USERNAME', '')
    password = env.get('OJ_PASSWORD', '')

    if not username or not password:
        return "❌ 错误：未配置OJ用户名或密码，请检查.env文件"

    # 1. 登录OJ
    client = httpx.Client(base_url=base_url, follow_redirects=True)
    try:
        login_resp = client.post('/login', json={'uname': username, 'password': password})
        login_resp.raise_for_status()

        # 检查登录是否成功
        has_sid = any(c.name == "sid" for c in client.cookies.jar)
        if not has_sid:
            return "❌ 错误：OJ登录失败，请检查用户名密码"
    except Exception as e:
        return f"❌ 错误：OJ登录失败 - {e}"

    # 2. 获取作业题目列表
    try:
        hw_resp = client.get(f'/homework/{homework_id}')
        if hw_resp.status_code != 200:
            return f"❌ 错误：获取作业详情失败 (HTTP {hw_resp.status_code})"

        # 解析题目列表
        pattern = (
            r'href="/p/([^"?]+)\?tid=' + re.escape(homework_id) +
            r'"[^>]*><b>([^<]+)</b>(?:&nbsp;|\s)*([^<]*)</a>'
        )
        problems = re.findall(pattern, hw_resp.text)

        if not problems:
            return f"❌ 错误：作业 {homework_id} 中未找到题目"
    except Exception as e:
        return f"❌ 错误：获取题目列表失败 - {e}"

    # 3. 获取提交记录
    try:
        record_resp = client.get(f'/record?tid={homework_id}&page=1')
        if record_resp.status_code != 200:
            return f"❌ 错误：获取提交记录失败 (HTTP {record_resp.status_code})"

        # 解析提交记录
        rows = re.findall(r'<tr[^>]*>(.*?)</tr>', record_resp.text, re.DOTALL)

        student_records = []
        for row in rows:
            # 检查是否包含用户和题目链接
            if "/user/" not in row or "/p/" not in row:
                continue

            # 提取学生姓名
            user_match = re.search(r'href="/user/\d+"[^>]*>(.*?)</a>', row, re.DOTALL)
            if not user_match:
                continue
            name = strip_tags(user_match.group(1))

            # 只处理目标学生
            if name != student_name:
                continue

            # 提取题目ID
            problem_match = re.search(r'href="/p/([^"?]+)', row)
            if not problem_match:
                continue
            problem_id = problem_match.group(1)

            # 提取状态
            status = detect_status(row)

            # 提取提交时间
            time_match = re.search(r'(\d{4}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{2}:\d{2})', row)
            submit_time = time_match.group(1) if time_match else ""

            student_records.append({
                'problem_id': problem_id,
                'status': status,
                'submit_time': submit_time
            })

    except Exception as e:
        return f"❌ 错误：解析提交记录失败 - {e}"

    # 4. 生成Markdown报告
    if not student_records:
        return f"📝 {student_name} 在本次作业中暂无提交记录"

    # 按题目分组统计
    problem_stats = {}
    for record in student_records:
        pid = record['problem_id']
        if pid not in problem_stats:
            problem_stats[pid] = {
                'attempts': 0,
                'statuses': [],
                'final_status': None
            }
        problem_stats[pid]['attempts'] += 1
        problem_stats[pid]['statuses'].append(record['status'])
        problem_stats[pid]['final_status'] = record['status']

    # 构建题目名称映射
    problem_names = {}
    for pid, code, name in problems:
        problem_names[pid] = name.strip() if name.strip() else code

    # 生成Markdown
    total_problems = len(problems)
    solved_problems = sum(1 for stats in problem_stats.values()
                         if stats['final_status'] == 'AC')
    total_submits = len(student_records)

    md_lines = [
        f"## 【OJ做题数据】",
        f"",
        f"**完成情况**: {solved_problems}/{total_problems} (共{total_submits}次提交)",
        f"",
        "| 题目 | 状态 | 提交次数 | 错误类型 |",
        "|------|------|----------|----------|",
    ]

    for pid, code, name in problems:
        if pid in problem_stats:
            stats = problem_stats[pid]
            status = "✅ 通过" if stats['final_status'] == 'AC' else "❌ 未通过"
            attempts = stats['attempts']

            # 统计错误类型
            error_types = []
            for s in stats['statuses']:
                if s not in ('AC', 'UNKNOWN'):
                    error_types.append(s)
            error_str = ", ".join(f"{e}×{error_types.count(e)}" for e in set(error_types)) if error_types else "—"

            problem_display = f"{code} {problem_names.get(pid, '')}".strip()
            md_lines.append(f"| {problem_display} | {status} | {attempts} | {error_str} |")
        else:
            problem_display = f"{code} {problem_names.get(pid, '')}".strip()
            md_lines.append(f"| {problem_display} | ⬜ 未提交 | 0 | — |")

    # 分析总结
    md_lines.extend([
        f"",
        f"**📊 分析**: {student_name}完成{solved_problems}/{total_problems}题"
    ])

    return "\n".join(md_lines)


def main():
    import argparse
    parser = argparse.ArgumentParser(description="获取学生OJ做题数据")
    parser.add_argument("--homework-id", required=True, help="作业ID")
    parser.add_argument("--student", required=True, help="学生姓名")
    args = parser.parse_args()

    result = get_student_oj_data(args.homework_id, args.student)
    print(result)


if __name__ == "__main__":
    main()
