# servidor_app.py
from flask import Flask, render_template, request, redirect, url_for, session, flash, jsonify
import mysql.connector
import random
import os
from datetime import datetime
from collections import defaultdict

app = Flask(__name__)
app.secret_key = os.urandom(24)

# --- CONFIGURAÇÃO DE ACESSOS ---
USERS = {
    "admin": "0112358",
    "tic": "0112358"
}
SENHA_DO_EXAME = "0112358"

# --- CONFIGURAÇÃO DA BASE DE DADOS ---
db_config = {
    'host': '127.0.0.1',
    'user': 'acesso_user',
    'password': 'Acesso_2@25',
    'database': 'acesso'
}

def get_db_connection():
    try:
        conn = mysql.connector.connect(**db_config)
        return conn
    except mysql.connector.Error as err:
        print(f"Erro de Base de Dados: {err}")
        return None

# --- ROTAS DE ACESSO E LOGIN ---
@app.route("/acesso-exame", methods=["GET", "POST"])
def acesso_exame():
    if request.method == "POST":
        senha_inserida = request.form.get('senha')
        if senha_inserida == SENHA_DO_EXAME:
            session['acesso_permitido'] = True
            return redirect(url_for('pagina_inscricao'))
        else:
            flash('Senha de acesso incorreta. Tente novamente.', 'error')
    return render_template("acesso_exame.html")

@app.route("/", methods=["GET"])
def pagina_inscricao():
    if session.get('acesso_permitido'):
        return render_template("inscricao.html")
    else:
        return redirect(url_for('acesso_exame'))

@app.route("/login", methods=["GET", "POST"])
def login():
    error = None
    if request.method == "POST":
        username = request.form.get('username')
        password = request.form.get('password')
        if username in USERS and USERS[username] == password:
            session['logged_in'] = True
            session['username'] = username
            return redirect(url_for('painel_admin'))
        else:
            error = "Utilizador ou palavra-passe incorreta."
    return render_template("login.html", error=error)

@app.route("/logout")
def logout():
    session.clear()
    return redirect(url_for('login'))

# --- ROTAS DO PROCESSO DE TESTE ---
@app.route("/iniciar-teste", methods=["POST"])
def iniciar_teste():
    numero_candidato = request.form['numero_candidato']
    nome_completo = request.form['nome_completo']
    curso_desejado = request.form['curso_desejado']

    conn = get_db_connection()
    if conn is None: return "<h1>Erro: Não foi possível ligar à base de dados.</h1>"
    cursor = conn.cursor(dictionary=True)

    sql_find_candidato = "SELECT id FROM candidatos WHERE numero_candidato = %s"
    cursor.execute(sql_find_candidato, (numero_candidato,))
    candidato_existente = cursor.fetchone()

    if candidato_existente:
        candidato_id = candidato_existente['id']
        # ### ALTERAÇÃO AQUI: Verifica se já existe um resultado "Aprovado" ###
        sql_check_aprovado = "SELECT id FROM resultados WHERE candidato_id = %s AND status = 'Aprovado'"
        cursor.execute(sql_check_aprovado, (candidato_id,))
        if cursor.fetchone():
            cursor.close()
            conn.close()
            return render_template("acesso_negado.html")
    else:
        sql_insert_candidato = "INSERT INTO candidatos (numero_candidato, nome_completo, curso_desejado) VALUES (%s, %s, %s)"
        cursor.execute(sql_insert_candidato, (numero_candidato, nome_completo, curso_desejado))
        conn.commit()
        candidato_id = cursor.lastrowid

    sql_select_teste = "SELECT id FROM testes WHERE curso_associado = %s LIMIT 1"
    cursor.execute(sql_select_teste, (curso_desejado,))
    resultado_teste = cursor.fetchone()

    if not resultado_teste:
        return f"<h1>Erro: Não existem testes disponíveis para o curso de {curso_desejado}.</h1>"
    
    teste_id = resultado_teste['id']
    cursor.close()
    conn.close()

    return render_template("regras.html", candidato_id=candidato_id, teste_id=teste_id, nome_candidato=nome_completo, numero_candidato=numero_candidato, curso_desejado=curso_desejado)

# ... (A rota /comecar-exame permanece igual) ...
@app.route("/comecar-exame", methods=["POST"])
def comecar_exame():
    candidato_id = request.form['candidato_id']
    teste_id = request.form['teste_id']
    nome_completo = request.form['nome_completo']
    numero_candidato = request.form['numero_candidato']
    curso_desejado = request.form['curso_desejado']

    conn = get_db_connection()
    if conn is None: return "<h1>Erro: Não foi possível ligar à base de dados.</h1>"
    cursor = conn.cursor(dictionary=True)

    perguntas_finais = []
    
    # --- ALTERAÇÃO PRINCIPAL AQUI: A SOMA DAS PERGUNTAS AGORA É 10 ---
    if curso_desejado == 'Ciências Criminais':
        categorias = {'Lógica': 3, 'Especialidade': 4, 'Língua Portuguesa': 3}

    elif curso_desejado == 'Hotelaria e Turismo':
        categorias = {'Lógica': 2, 'Especialidade': 4, 'Língua Portuguesa': 4}

    elif curso_desejado in ['Logística e Gestão Comercial', 'Contabilidade e Finanças']:
        categorias = {'Matemática': 4, 'Lógica': 2, 'Especialidade': 4}

    elif curso_desejado in ['Direito', 'Gestão de Recursos Humanos']:
        categorias = {'Lógica': 2, 'Especialidade': 4, 'Língua Portuguesa': 4}

    else: # Engenharias
        categorias = {'Matemática': 1, 'Lógica': 2, 'Especialidade': 2}

    categorias_necessarias = list(categorias.keys())
    placeholders = ','.join(['%s'] * len(categorias_necessarias))
    sql_todas_as_perguntas = f"""
        SELECT id, enunciado, opcao_a, opcao_b, opcao_c, opcao_d, categoria 
        FROM perguntas 
        WHERE teste_id = %s AND categoria IN ({placeholders})
    """
    params = [teste_id] + categorias_necessarias
    cursor.execute(sql_todas_as_perguntas, tuple(params))
    perguntas_disponiveis = cursor.fetchall()

    pool_por_categoria = {cat: [] for cat in categorias_necessarias}
    for p in perguntas_disponiveis:
        pool_por_categoria[p['categoria']].append(p)

    for categoria, limite in categorias.items():
        pool_da_categoria = pool_por_categoria.get(categoria, [])
        
        if len(pool_da_categoria) < limite:
            cursor.close()
            conn.close()
            return f"<h1>Erro: O banco de perguntas para '{curso_desejado}' não tem perguntas suficientes na categoria '{categoria}'. Precisa de {limite}, mas só existem {len(pool_da_categoria)}.</h1>"
        
        perguntas_selecionadas = random.sample(pool_da_categoria, limite)
        perguntas_finais.extend(perguntas_selecionadas)

    random.shuffle(perguntas_finais)
    
    cursor.close()
    conn.close()

    return render_template("teste.html", 
                           candidato_id=candidato_id,
                           teste_id=teste_id,
                           nome_candidato=nome_completo,
                           numero_candidato=numero_candidato,
                           curso=curso_desejado,
                           perguntas=perguntas_finais)

# ... (A rota /submeter-teste permanece igual) ...
@app.route("/submeter-teste", methods=["POST"])
def submeter_teste():
    candidato_id = request.form['candidato_id']
    teste_id = request.form['teste_id']
    ordem_perguntas_str = request.form.get('ordem_perguntas', '')
    ordem_perguntas = ordem_perguntas_str.split(',')
    tentativa_fraude = request.form.get('tentativa_fraude', '0') == '1'
    conn = get_db_connection()
    if conn is None: return "<h1>Erro: Não foi possível ligar à base de dados.</h1>"
    cursor = conn.cursor(dictionary=True)

    ids_perguntas = [key.split('_')[1] for key in request.form if key.startswith('pergunta_')]
    if not ids_perguntas and ordem_perguntas: ids_perguntas = ordem_perguntas
    if not ids_perguntas or ids_perguntas == ['']: return "<h1>Erro: Nenhuma pergunta foi submetida.</h1>"

    sql_perguntas = f"SELECT id, resposta_correta FROM perguntas WHERE id IN ({','.join(['%s'] * len(ids_perguntas))})"
    cursor.execute(sql_perguntas, ids_perguntas)
    perguntas_db_dict = {p['id']: p['resposta_correta'] for p in cursor.fetchall()}

    respostas_corretas = 0
    respostas_para_inserir = []

    for i, pergunta_id_str in enumerate(ordem_perguntas):
        pergunta_id = int(pergunta_id_str)
        resposta_correta = perguntas_db_dict.get(pergunta_id)
        resposta_dada = request.form.get(f'pergunta_{pergunta_id}')
        ordem = i + 1
        foi_correta = (resposta_dada == resposta_correta)
        if foi_correta:
            respostas_corretas += 1
        respostas_para_inserir.append((pergunta_id, resposta_dada if resposta_dada else 'N/A', foi_correta, ordem))

    nota_final = 0.0 if tentativa_fraude else (respostas_corretas / len(ordem_perguntas)) * 20
    status = "Aprovado" if nota_final >= 10 else "Reprovado"
    
    sql_insert_resultado = "INSERT INTO resultados (candidato_id, teste_id, nota_final, status, tentativa_fraude) VALUES (%s, %s, %s, %s, %s)"
    cursor.execute(sql_insert_resultado, (candidato_id, teste_id, nota_final, status, tentativa_fraude))
    conn.commit()
    resultado_id = cursor.lastrowid
    
    sql_insert_respostas = "INSERT INTO respostas_candidato (resultado_id, pergunta_id, resposta_dada, foi_correta, ordem) VALUES (%s, %s, %s, %s, %s)"
    dados_respostas = [(resultado_id,) + resp for resp in respostas_para_inserir]
    cursor.executemany(sql_insert_respostas, dados_respostas)
    conn.commit()
    
    cursor.close()
    conn.close()
    
    return redirect(url_for('pagina_resultado', resultado_id=resultado_id))

# ... (A rota /resultado permanece igual) ...
@app.route("/resultado/<int:resultado_id>")
def pagina_resultado(resultado_id):
    conn = get_db_connection()
    if conn is None: return "<h1>Erro: Não foi possível ligar à base de dados.</h1>"
    cursor = conn.cursor(dictionary=True)
    
    sql_resultado = "SELECT r.nota_final, r.status, r.tentativa_fraude, c.nome_completo FROM resultados r JOIN candidatos c ON r.candidato_id = c.id WHERE r.id = %s"
    cursor.execute(sql_resultado, (resultado_id,))
    resultado = cursor.fetchone()
    resultado['nome_candidato'] = resultado.pop('nome_completo')
    
    sql_correcao = """
        SELECT p.enunciado, p.opcao_a, p.opcao_b, p.opcao_c, p.opcao_d, 
               rc.resposta_dada, p.resposta_correta, rc.foi_correta
        FROM respostas_candidato rc 
        JOIN perguntas p ON rc.pergunta_id = p.id
        WHERE rc.resultado_id = %s
        ORDER BY rc.ordem ASC; 
    """
    
    cursor.execute(sql_correcao, (resultado_id,))
    correcao = cursor.fetchall()
    
    cursor.close()
    conn.close()
    
    return render_template("resultado.html", resultado=resultado, correcao=correcao)

# --- ROTAS DE ADMINISTRAÇÃO ---
@app.route("/admin")
def painel_admin():
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    curso_filtro = request.args.get('curso_filtro', 'todos') 
    data_inicio = request.args.get('data_inicio', '')
    data_fim = request.args.get('data_fim', '')
    conn = get_db_connection()
    if conn is None: return "<h1>Erro: Não foi possível ligar à base de dados.</h1>"
    cursor = conn.cursor(dictionary=True)
    
    sql_base = "SELECT c.id AS candidato_id, r.id AS resultado_id, c.numero_candidato, c.nome_completo, c.curso_desejado, r.nota_final, r.status, r.data_submissao, r.tentativa_fraude FROM resultados r JOIN candidatos c ON r.candidato_id = c.id"
    conditions = []
    params = []
    if curso_filtro != 'todos':
        conditions.append("c.curso_desejado = %s")
        params.append(curso_filtro)
    if data_inicio:
        conditions.append("r.data_submissao >= %s")
        params.append(data_inicio)
    if data_fim:
        conditions.append("r.data_submissao <= %s")
        params.append(data_fim + ' 23:59:59')
    if conditions:
        sql_base += " WHERE " + " AND ".join(conditions)
    sql_base += " ORDER BY r.data_submissao DESC;"
    cursor.execute(sql_base, tuple(params))
    resultados = cursor.fetchall()
    cursor.close()
    conn.close()
    
    return render_template("admin.html", 
                           resultados=resultados, 
                           curso_selecionado=curso_filtro, 
                           data_inicio=data_inicio, 
                           data_fim=data_fim,
                           now=datetime.now())

@app.route("/apagar_candidato/<int:candidato_id>", methods=["POST"])
def apagar_candidato(candidato_id):
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    
    conn = get_db_connection()
    if conn is None: 
        flash("Erro de base de dados.", "error")
        return redirect(url_for('painel_admin'))
    
    cursor = conn.cursor(dictionary=True)
    
    try:
        # 1. Obter os dados do candidato para o histórico
        cursor.execute("SELECT numero_candidato, nome_completo, curso_desejado FROM candidatos WHERE id = %s", (candidato_id,))
        candidato_info = cursor.fetchone()
        
        if candidato_info:
            # 2. Inserir no histórico
            user_que_apagou = session.get('username', 'desconhecido')
            detalhes = f"Candidato: {candidato_info['nome_completo']} ({candidato_info['numero_candidato']}) - Curso: {candidato_info['curso_desejado']}"
            
            sql_log = "INSERT INTO historico_acoes (utilizador, acao, detalhes, data_acao) VALUES (%s, %s, %s, NOW())"
            log_cursor = conn.cursor()
            log_cursor.execute(sql_log, (user_que_apagou, 'apagar_candidato', detalhes))
            log_cursor.close()

        # 3. Apagar o candidato (as outras tabelas são apagadas em cascata se configurado na BD)
        sql_delete = "DELETE FROM candidatos WHERE id = %s"
        delete_cursor = conn.cursor()
        delete_cursor.execute(sql_delete, (candidato_id,))
        delete_cursor.close()
        
        conn.commit()
        flash("Candidato apagado com sucesso e ação registada no histórico.", "success")
        
    except mysql.connector.Error as err:
        print(f"Erro ao apagar o candidato: {err}")
        flash("Ocorreu um erro ao apagar o candidato.", "error")
    finally:
        cursor.close()
        conn.close()
        
    return redirect(url_for('painel_admin'))

@app.route("/admin/ver_prova/<int:resultado_id>")
def ver_prova(resultado_id):
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    conn = get_db_connection()
    if conn is None: return "<h1>Erro: Não foi possível ligar à base de dados.</h1>"
    cursor = conn.cursor(dictionary=True)

    sql_resultado = "SELECT r.*, c.nome_completo, c.numero_candidato, c.curso_desejado FROM resultados r JOIN candidatos c ON r.candidato_id = c.id WHERE r.id = %s"
    cursor.execute(sql_resultado, (resultado_id,))
    resultado = cursor.fetchone()
    if not resultado:
        return "<h1>Erro: Resultado não encontrado.</h1>"

    sql_prova = """
        SELECT p.enunciado, p.opcao_a, p.opcao_b, p.opcao_c, p.opcao_d, 
               rc.resposta_dada, p.resposta_correta, rc.foi_correta
        FROM respostas_candidato rc 
        JOIN perguntas p ON rc.pergunta_id = p.id
        WHERE rc.resultado_id = %s
        ORDER BY rc.ordem ASC; 
    """
    cursor.execute(sql_prova, (resultado_id,))
    prova = cursor.fetchall()
    
    cursor.close()
    conn.close()
    
    return render_template("ver_prova.html", resultado=resultado, candidato=resultado, prova=prova)

# --- ROTAS DE ESTATÍSTICAS ---

@app.route("/admin/estatisticas")
def estatisticas_page():
    """Renderiza a página HTML que irá mostrar os gráficos."""
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    return render_template("estatisticas.html")

@app.route("/admin/estatisticas_data")
def estatisticas_data():
    """Fornece os dados para todos os gráficos em formato JSON."""
    if not session.get('logged_in'):
        return jsonify({"error": "Não autorizado"}), 401

    conn = get_db_connection()
    if conn is None:
        return jsonify({"error": "Erro de base de dados"}), 500
    cursor = conn.cursor(dictionary=True)

    # --- 1. Dados Quantitativos (Aprovados/Reprovados por Curso) ---
    query_quantitativo = """
        SELECT 
            c.curso_desejado,
            COUNT(r.id) AS total_testes,
            SUM(CASE WHEN r.status = 'Aprovado' THEN 1 ELSE 0 END) AS total_aprovados,
            SUM(r.tentativa_fraude) AS total_fraudes
        FROM resultados r
        JOIN candidatos c ON r.candidato_id = c.id
        GROUP BY c.curso_desejado
        ORDER BY c.curso_desejado;
    """
    cursor.execute(query_quantitativo)
    dados_quantitativos = cursor.fetchall()
    
    # Adicionar totais
    total_geral = {
        "curso_desejado": "TOTAL GERAL",
        "total_testes": sum(d['total_testes'] for d in dados_quantitativos),
        "total_aprovados": sum(d['total_aprovados'] for d in dados_quantitativos),
        "total_fraudes": sum(d['total_fraudes'] for d in dados_quantitativos)
    }
    dados_quantitativos.append(total_geral)
    
    # --- 2. Desempenho por Categoria ---
    query_categoria = """
        SELECT 
            c.curso_desejado,
            p.categoria,
            SUM(rc.foi_correta) AS acertos,
            COUNT(rc.id) AS total_respostas
        FROM respostas_candidato rc
        JOIN perguntas p ON rc.pergunta_id = p.id
        JOIN resultados r ON rc.resultado_id = r.id
        JOIN candidatos c ON r.candidato_id = c.id
        GROUP BY c.curso_desejado, p.categoria
        ORDER BY c.curso_desejado, p.categoria;
    """
    cursor.execute(query_categoria)
    desempenho_db = cursor.fetchall()
    
    desempenho_por_curso = defaultdict(lambda: {'labels': [], 'data': []})
    for row in desempenho_db:
        curso = row['curso_desejado']
        taxa_acerto = (row['acertos'] / row['total_respostas']) * 100 if row['total_respostas'] > 0 else 0
        desempenho_por_curso[curso]['labels'].append(row['categoria'])
        desempenho_por_curso[curso]['data'].append(round(taxa_acerto, 2))

    # --- 3. Perguntas Mais Difíceis e Fáceis ---
    query_perguntas = """
        SELECT 
            p.enunciado,
            SUM(rc.foi_correta) AS acertos,
            COUNT(rc.id) AS total,
            (SUM(rc.foi_correta) / COUNT(rc.id)) * 100 AS taxa_acerto
        FROM respostas_candidato rc
        JOIN perguntas p ON rc.pergunta_id = p.id
        GROUP BY p.id, p.enunciado
        HAVING COUNT(rc.id) > 4 -- Apenas perguntas respondidas 5+ vezes
    """
    cursor.execute(f"{query_perguntas} ORDER BY taxa_acerto ASC LIMIT 5;")
    perguntas_dificeis = cursor.fetchall()
    
    cursor.execute(f"{query_perguntas} ORDER BY taxa_acerto DESC LIMIT 5;")
    perguntas_faceis = cursor.fetchall()

    # --- 4. Distribuição de Notas (Histograma) ---
    query_histograma = """
        SELECT 
            SUM(CASE WHEN nota_final >= 0 AND nota_final < 5 THEN 1 ELSE 0 END) AS '0-4',
            SUM(CASE WHEN nota_final >= 5 AND nota_final < 10 THEN 1 ELSE 0 END) AS '5-9',
            SUM(CASE WHEN nota_final >= 10 AND nota_final < 15 THEN 1 ELSE 0 END) AS '10-14',
            SUM(CASE WHEN nota_final >= 15 AND nota_final <= 20 THEN 1 ELSE 0 END) AS '15-20'
        FROM resultados;
    """
    cursor.execute(query_histograma)
    dist_notas_db = cursor.fetchone()
    distribuicao_notas = {
        "labels": list(dist_notas_db.keys()),
        "data": [int(v) if v is not None else 0 for v in dist_notas_db.values()]
    }

    # --- 5. Evolução ao Longo do Tempo ---
    query_evolucao = """
        SELECT 
            DATE(data_submissao) as dia,
            COUNT(id) as total_testes,
            SUM(CASE WHEN status = 'Aprovado' THEN 1 ELSE 0 END) as total_aprovados
        FROM resultados
        GROUP BY DATE(data_submissao)
        ORDER BY dia;
    """
    cursor.execute(query_evolucao)
    evolucao_db = cursor.fetchall()
    evolucao_tempo = {
        "labels": [row['dia'].strftime('%d/%m') for row in evolucao_db],
        "testesData": [row['total_testes'] for row in evolucao_db],
        "aprovadosData": [row['total_aprovados'] for row in evolucao_db]
    }

    cursor.close()
    conn.close()

    # --- Compilar todos os dados para a resposta JSON ---
    data_para_graficos = {
        "dadosQuantitativos": dados_quantitativos,
        "desempenhoPorCurso": desempenho_por_curso,
        "perguntasDificeis": perguntas_dificeis,
        "perguntasFaceis": perguntas_faceis,
        "distribuicaoNotas": distribuicao_notas,
        "evolucaoTempo": evolucao_tempo
    }

    return jsonify(data_para_graficos)


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8502, debug=True)
