"""Pruebas unitarias del dominio puro reacciones_grader (SDD/TDD).

Formato SAQI-nivel unidad: cubren calificación por tema sobre 100, normalización
de respuesta corta, descuento por incidentes y piso en 0.
"""

import unittest

import reacciones_grader as g


N_2_INCIDENTES = 2


def respuestas_perfectas():
    return {
        "4.1.1": {"0": "B", "1": "A", "2": "C", "3": "D", "4": "B"},
        "4.1.2": {"0": "A", "1": "B", "2": "A", "3": "C", "4": "D"},
        "4.1.3": {"0": "reactivos", "1": "productos", "2": "ecuacionquimica",
                  "3": "coeficiente", "4": "gaseoso"},
        "4.1.4": {"0": "sintesis", "1": "descomposicion",
                  "2": "sustitucionsimple", "3": "doblesustitucion",
                  "4": "combustion", "5": "sintesis", "6": "descomposicion",
                  "7": "sustitucionsimple", "8": "doblesustitucion",
                  "9": "combustion"},
    }


class TestCalificacionTema(unittest.TestCase):

    def test_tema_100_perfecto(self):
        r = g.calificar_tema("4.1.1", {"0": "B", "1": "A", "2": "C",
                                       "3": "D", "4": "B"})
        self.assertEqual(r["puntos"], 5)
        self.assertEqual(r["nota_100"], 100)

    def test_tema_parcial_80(self):
        # 4 de 5 correctos en 4.1.1 (falla el índice 3).
        resp = {"0": "B", "1": "A", "2": "C", "3": "A", "4": "B"}
        r = g.calificar_tema("4.1.1", resp)
        self.assertEqual(r["puntos"], 4)
        self.assertEqual(r["nota_100"], 80)

    def test_tema_vacio_0(self):
        r = g.calificar_tema("4.1.2", {})
        self.assertEqual(r["puntos"], 0)
        self.assertEqual(r["nota_100"], 0)

    def test_4_1_4_con_10_items(self):
        r = g.calificar_tema("4.1.4", {
            "0": "sintesis", "1": "descomposicion", "2": "sustitucionsimple",
            "3": "doblesustitucion", "4": "combustion", "5": "sintesis",
            "6": "descomposicion", "7": "sustitucionsimple",
            "8": "doblesustitucion", "9": "combustion"})

    def test_tema_desconocido_levanta(self):
        with self.assertRaises(ValueError):
            g.calificar_tema("9.9.9", {})


class TestNormalizacion(unittest.TestCase):

    def test_acentos_y_espacios(self):
        self.assertEqual(g.normalizar("  Ecuación Química "),
                         "ecuacionquimica")
        self.assertEqual(g.normalizar("REACTIVOS"), "reactivos")
        self.assertEqual(g.normalizar("doble sustitución"),
                         "doblesustitucion")

    def test_acepta_con_guion_bajo(self):
        self.assertEqual(g.normalizar("sustitucion_simple"),
                         "sustitucionsimple")


class TestDescuentoIncidencias(unittest.TestCase):

    def test_descuento_por_incidencias(self):
        # 100 - 5*2 = 90
        self.assertEqual(g.nota_final(100, 2), 90)

    def test_piso_en_cero(self):
        self.assertEqual(g.nota_final(100, 30), 0)
        self.assertEqual(g.nota_final(80, 20), 0)


class TestCalificarExamen(unittest.TestCase):

    def test_perfecto_sin_incidentes(self):
        res = g.calificar_examen(respuestas_perfectas(), 0)
        for tema in ("4.1.1", "4.1.2", "4.1.3", "4.1.4"):
            self.assertEqual(res["notas"][tema], 100)
        self.assertEqual(res["nota_final"], 100)
        self.assertEqual(res["descuento_total"], 0)

    def test_perfecto_con_incidentes_descunta_cada_tema(self):
        res = g.calificar_examen(respuestas_perfectas(), N_2_INCIDENTES)
        for tema in ("4.1.1", "4.1.2", "4.1.3", "4.1.4"):
            self.assertEqual(res["notas"][tema], 90)
        self.assertEqual(res["nota_final"], 90)
        self.assertEqual(res["descuento_total"], 10)


class TestNotaModulo(unittest.TestCase):

    def test_nota_modulo_perfecta(self):
        nota = g.nota_modulo(respuestas_perfectas(), 0)
        self.assertEqual(nota, 100)

    def test_nota_modulo_con_incidentes(self):
        nota = g.nota_modulo(respuestas_perfectas(), 2)
        self.assertEqual(nota, 90)

    def test_nota_modulo_parcial(self):
        # Solo responde correctamente 4.1.1 (5 puntos de 25 totales)
        resp = {
            "4.1.1": {"0": "B", "1": "A", "2": "C", "3": "D", "4": "B"},
            "4.1.2": {}, "4.1.3": {}, "4.1.4": {}
        }
        nota = g.nota_modulo(resp, 0)
        # 5/25 = 20%
        self.assertEqual(nota, 20)

    def test_nota_modulo_vacia(self):
        nota = g.nota_modulo({}, 0)
        self.assertEqual(nota, 0)


if __name__ == "__main__":
    unittest.main()