#!/usr/bin/env python3
"""
Gerenciador e orquestrador do processo de correção de Provas Escritas — Inteligência Artificial II (2026.2).
Suporta controle de auditoria/status, divisão em lotes (batches), extração de páginas em alta resolução e consolidação de notas.
Suporta múltiplas provas via argumento --prova (ex: prova-1, prova-2, final).
"""

import os
import sys
import json
import subprocess
import argparse
import re

SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
PROVAS_ROOT = os.path.dirname(SCRIPTS_DIR)

LOTES = {
    1: list(range(1, 7)),    # 1 a 6 (6 alunos)
    2: list(range(7, 13)),   # 7 a 12 (6 alunos)
    3: list(range(13, 19)),  # 13 a 18 (6 alunos)
    4: list(range(19, 25)),  # 19 a 24 (6 alunos)
    5: list(range(25, 30)),  # 25 a 29 (5 alunos)
    6: list(range(30, 34)),  # 30 a 33 (4 alunos)
}

def get_paths(prova="prova-1"):
    prova_dir = os.path.join(PROVAS_ROOT, prova)
    return {
        "prova_dir": prova_dir,
        "scanner_dir": os.path.join(prova_dir, "digitalizacoes"),
        "transcricoes_dir": os.path.join(prova_dir, "transcricoes"),
        "laudos_dir": os.path.join(prova_dir, "laudos"),
        "dados_dir": os.path.join(prova_dir, "dados"),
        "map_file": os.path.join(prova_dir, "dados", "mapeamento_provas.json"),
        "csv_file": os.path.join(prova_dir, "dados", f"notas_{prova.replace('-', '')}.csv"),
        "scratch_dir": os.path.join(prova_dir, ".scratch_processamento"),
    }

def carregar_dados(paths):
    if not os.path.exists(paths["map_file"]):
        print(f"Aviso: Arquivo de mapeamento não encontrado em {paths['map_file']}")
        return []
    with open(paths["map_file"], "r", encoding="utf-8") as f:
        return json.load(f)

def obter_status_aluno(item, paths):
    nome = item["nome"]
    matricula = item["matricula"]
    
    qmd_file = f"{nome} - {matricula}.qmd" if matricula else f"{nome}.qmd"
    md_file = f"{nome} - {matricula}.md" if matricula else f"{nome}.md"
    html_file = f"{nome} - {matricula}_correcao.html" if matricula else f"{nome}_correcao.html"
    
    qmd_path = os.path.join(paths["transcricoes_dir"], qmd_file)
    md_path = os.path.join(paths["transcricoes_dir"], md_file)
    html_path = os.path.join(paths["laudos_dir"], html_file)
    
    has_transcricao = os.path.exists(qmd_path) or os.path.exists(md_path)
    transcricao_path = qmd_path if os.path.exists(qmd_path) else md_path
    has_html = os.path.exists(html_path)
    
    legibilidade = "—"
    nota = "—"
    
    if has_transcricao:
        try:
            with open(transcricao_path, "r", encoding="utf-8") as f:
                content = f.read()
                m_leg = re.search(r'(?:legibilidade_global|legibilidade_percentual|taxa_legibilidade_estimada|Taxa de Legibilidade Estimada)[*:]*\s*[\"\\\']?(\d+)%?', content, re.IGNORECASE)
                if m_leg:
                    legibilidade = f"{m_leg.group(1)}%"
        except Exception:
            pass
            
    q_notas = ["—", "—", "—", "—", "—"]
    if has_html:
        try:
            with open(html_path, "r", encoding="utf-8") as f:
                content = f.read()
                m_nota = re.search(r'score-val[\"\\\']?>([\d,]+)<', content)
                if m_nota:
                    nota = m_nota.group(1)
                
                # Extrair notas individuais das 5 questões
                pills = re.findall(r'class=[\"\\\'](?:score-pill|q-total-score|q-score|questao-score)[^\"\\\']*[\"\\\']?>([\d,]+)\s*/\s*5,0', content)
                if len(pills) >= 5:
                    q_notas = pills[:5]
        except Exception:
            pass
            
    return {
        "id": item["id"],
        "nome": nome,
        "matricula": matricula,
        "turma": item.get("turma", "—"),
        "has_qmd": has_transcricao,
        "has_html": has_html,
        "legibilidade": legibilidade,
        "nota": nota,
        "q_notas": q_notas,
        "arquivo_scanner": item.get("arquivo_scanner", "")
    }

def cmd_status(paths, prova_nome):
    dados = carregar_dados(paths)
    if not dados:
        return
    print("=" * 95)
    print(f"STATUS GERAL DA CORREÇÃO — {prova_nome.upper()} IA II (2026.2)")
    print("=" * 95)
    print(f"{'#':<3} | {'Discente':<32} | {'Matrícula':<12} | {'Turma':<7} | {'QMD':<4} | {'HTML':<5} | {'Legib.':<7} | {'Nota':<6}")
    print("-" * 95)
    
    total_qmd = 0
    total_html = 0
    
    for item in dados:
        st = obter_status_aluno(item, paths)
        qmd_mark = "✅" if st["has_qmd"] else "⚪"
        html_mark = "✅" if st["has_html"] else "⚪"
        if st["has_qmd"]: total_qmd += 1
        if st["has_html"]: total_html += 1
        
        print(f"{st['id']:<3} | {st['nome'][:32]:<32} | {st['matricula']:<12} | {st['turma']:<7} | {qmd_mark:<4} | {html_mark:<5} | {st['legibilidade']:<7} | {st['nota']:<6}")
        
    print("-" * 95)
    n_total = len(dados)
    print(f"Progresso: Transcrições QMD: {total_qmd}/{n_total} ({total_qmd/n_total*100:.1f}%) | Laudos HTML: {total_html}/{n_total} ({total_html/n_total*100:.1f}%)")
    print("=" * 95)

def cmd_lotes(paths):
    dados = {d["id"]: d for d in carregar_dados(paths)}
    if not dados:
        return
    print("\n📦 ESTRUTURAÇÃO DE PROCESSAMENTO EM LOTES (IA II):")
    for lote_num, ids in LOTES.items():
        print(f"\n--- LOTE {lote_num} (IDs {ids[0]:02d} a {ids[-1]:02d} — {len(ids)} alunos) ---")
        for i in ids:
            d = dados[i]
            st = obter_status_aluno(d, paths)
            status_str = "Concluído" if (st["has_qmd"] and st["has_html"]) else ("Transcrito" if st["has_qmd"] else "Pendente")
            print(f"  [{d['id']:02d}] {d['nome']} ({d['matricula'] if d['matricula'] else 'S/Matrícula'}) [{d['turma']}] -> {status_str}")

def cmd_extrair(paths, lote_num=None, aluno_id=None):
    dados = {d["id"]: d for d in carregar_dados(paths)}
    if not dados:
        return
    ids_alvo = []
    
    if aluno_id:
        if aluno_id in dados:
            ids_alvo.append(aluno_id)
        else:
            print(f"ID de aluno {aluno_id} inválido.")
            return
    elif lote_num:
        if lote_num in LOTES:
            ids_alvo = LOTES[lote_num]
        else:
            print(f"Lote {lote_num} inválido (escolha de 1 a 6).")
            return
    else:
        print("Especifique --lote N ou --aluno ID")
        return

    os.makedirs(paths["scratch_dir"], exist_ok=True)
    
    for aid in ids_alvo:
        d = dados[aid]
        pdf_path = os.path.join(paths["scanner_dir"], d["arquivo_scanner"])
        
        aluno_out_dir = os.path.join(paths["scratch_dir"], f"aluno_{aid:02d}_{d['matricula'] if d['matricula'] else 'sem_mat'}")
        os.makedirs(aluno_out_dir, exist_ok=True)
        
        prefix = os.path.join(aluno_out_dir, "page")
        print(f"Extraindo páginas de [{aid:02d}] {d['nome']}...")
        cmd = ["pdftoppm", "-png", "-r", "150", pdf_path, prefix]
        subprocess.run(cmd, check=True)
        
    print(f"\n✅ Extração concluída em: {paths['scratch_dir']}")

def cmd_exportar_csv(paths):
    dados = carregar_dados(paths)
    if not dados:
        return
    csv_file = paths["csv_file"]
    import csv
    
    os.makedirs(os.path.dirname(csv_file), exist_ok=True)
    with open(csv_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["id", "nome", "matricula", "turma", "legibilidade", "q1", "q2", "q3", "q4", "q5", "nota_total"])
        
        for item in dados:
            st = obter_status_aluno(item, paths)
            q1, q2, q3, q4, q5 = st["q_notas"]
            writer.writerow([
                st["id"],
                st["nome"],
                st["matricula"],
                st["turma"],
                st["legibilidade"],
                q1,
                q2,
                q3,
                q4,
                q5,
                st["nota"]
            ])
            
    print(f"✅ Tabela consolidada de notas exportada com sucesso em: {csv_file}")

def main():
    parser = argparse.ArgumentParser(description="Gerenciador de Correções de Provas Escritas — IA II")
    parser.add_argument("--prova", default="prova-1", help="Nome da prova (padrão: prova-1)")
    parser.add_argument("--status", action="store_true", help="Exibe tabela de status geral")
    parser.add_argument("--lotes", action="store_true", help="Lista a composição de cada lote")
    parser.add_argument("--extrair", action="store_true", help="Extrai imagens das páginas de um lote ou aluno")
    parser.add_argument("--exportar-csv", action="store_true", help="Exporta notas consolidadas em CSV")
    parser.add_argument("--lote", type=int, help="Número do lote (1 a 6)")
    parser.add_argument("--aluno", type=int, help="ID do aluno (1 a 33)")
    
    args = parser.parse_args()
    paths = get_paths(args.prova)
    
    if args.status:
        cmd_status(paths, args.prova)
    elif args.lotes:
        cmd_lotes(paths)
    elif args.extrair:
        cmd_extrair(paths, args.lote, args.aluno)
    elif args.exportar_csv:
        cmd_exportar_csv(paths)
    else:
        cmd_status(paths, args.prova)

if __name__ == "__main__":
    main()
