from flask import session
from collections import defaultdict
from scripts.ens_controls import ENSControlLoader

class EvaluadorENS:
    """
    Gestiona la carga de preguntas (controles ENS) y el guardado de respuestas:
      - get_controles(): devuelve lista de controles con 'codigo', 'nombre', 'descripcion', 'pregunta'
      - save_respuestas(form_data): procesa request.form y guarda en session['evaluacion_controles']
      - calculate_stats(respuestas): calcula porcentajes de cumplimiento / parcial / no cumple
      - calculate_group_stats(respuestas): estadística por familia de controles (p.ej. 'OP.ACC', 'OP.CONT', etc.)
      - format_resumen(...) : genera un texto con el resumen completo (global + por grupos + detalle)
    """

    def __init__(self):
        loader = ENSControlLoader()
        self.controles = loader.load_questions()  # lista de dicts con 'codigo','nombre','descripcion','pregunta'

    def get_controles(self):
        """
        Devuelve la lista de controles para iterar en el formulario.
        Cada control es un dict con: codigo, nombre, descripcion, pregunta.
        """
        return self.controles

    def save_respuestas(self, form_data):
        """
        Toma los datos de request.form (ImmutableMultiDict) y genera
        una lista de dicts con { codigo, respuesta, porcentaje }:
          - respuesta en {'cumple', 'parcial', 'no_cumple'}
          - si respuesta == 'parcial', se lee <codigo>_porcentaje como int 1–99.
        Luego guarda en session['evaluacion_controles'] y devuelve esa lista.
        """
        respuestas = []
        for c in self.controles:
            codigo = c['codigo']
            clave_resp = f"{codigo}_respuesta"
            valor = form_data.get(clave_resp)

            if valor not in ('cumple', 'parcial', 'no_cumple'):
                valor = 'no_cumple'

            porcentaje = None
            if valor == 'parcial':
                clave_pct = f"{codigo}_porcentaje"
                try:
                    pct = int(form_data.get(clave_pct, 0))
                    if 1 <= pct <= 99:
                        porcentaje = pct
                except ValueError:
                    porcentaje = None

            respuestas.append({
                'codigo': codigo,
                'respuesta': valor,
                'porcentaje': porcentaje
            })

        session['evaluacion_controles'] = respuestas
        return respuestas

    def calculate_stats(self, respuestas):
        """
        A partir de la lista de respuestas (cada elemento con 'respuesta' y 'porcentaje'),
        calcula:
          - % de controles que cumplen totalmente
          - % de controles que cumplen parcialmente (sumando % parciales normalizados)
          - % de controles que no cumplen
        Devuelve {'cumple': X, 'parcial': Y, 'no_cumple': Z} (sumatorio = 100).
        """
        total = len(respuestas)
        if total == 0:
            return {'cumple': 0, 'parcial': 0, 'no_cumple': 0}

        count_cumple = 0
        sum_parcial = 0.0
        count_no = 0

        for r in respuestas:
            if r['respuesta'] == 'cumple':
                count_cumple += 1
            elif r['respuesta'] == 'parcial' and r['porcentaje'] is not None:
                sum_parcial += (r['porcentaje'] / 100.0)
            else:
                count_no += 1

        pct_cumple = round((count_cumple / total) * 100)
        pct_parcial = round((sum_parcial / total) * 100)
        pct_no = 100 - pct_cumple - pct_parcial

        return {
            'cumple': pct_cumple,
            'parcial': pct_parcial,
            'no_cumple': pct_no
        }

    def calculate_group_stats(self, respuestas):
        """
        Calcula estadísticas por familia de controles.
        Agrupa por prefijo:
        - Si el código es AAA.BBB.CCC → familia 'AAA.BBB'
        - Si el código es AAA.1 (o .2, .3…) → familia 'AAA'
        """
        grupos = defaultdict(list)
        for r in respuestas:
            partes = r['codigo'].split('.', 2)
            if len(partes) >= 2:
                if partes[1].isdigit():
                    familia = partes[0]
                else:
                    familia = '.'.join(partes[:2])
            else:
                familia = r['codigo']
            grupos[familia].append(r)

        resultado = []
        for familia, items in sorted(grupos.items()):
            total = len(items)
            if total == 0:
                stats = {'cumple': 0, 'parcial': 0, 'no_cumple': 0}
            else:
                count_cumple = sum(1 for r in items if r['respuesta'] == 'cumple')
                sum_parcial = sum((r['porcentaje'] or 0) / 100.0
                                for r in items if r['respuesta'] == 'parcial')
                count_no = total - count_cumple - sum(1 for r in items
                                                    if r['respuesta'] == 'parcial' and r['porcentaje'] is not None)
                pct_cumple = round((count_cumple / total) * 100)
                pct_parcial = round((sum_parcial / total) * 100)
                pct_no = 100 - pct_cumple - pct_parcial
                stats = {'cumple': pct_cumple, 'parcial': pct_parcial, 'no_cumple': pct_no}

            resultado.append({
                'familia': familia,
                'total': total,
                'cumple': stats['cumple'],
                'parcial': stats['parcial'],
                'no_cumple': stats['no_cumple']
            })

        return resultado


    def format_resumen(self, respuestas, stats, group_stats):
        """
        Genera un texto plano con el resumen completo, para descargar:
          - Estadística global (% cumple, % parcial, % no cumple)
          - Estadística por familia (listado de familias con sus %)
          - Detalle de cada control (código: estado)
        """
        lines = []
        lines.append("=== Resumen Evaluación ENS Nivel Alto ===\n")
        lines.append(">> Estadística Global:")
        lines.append(f"   - Controles que cumplen totalmente: {stats['cumple']}%")
        lines.append(f"   - Controles que cumplen parcialmente: {stats['parcial']}%")
        lines.append(f"   - Controles que no cumplen: {stats['no_cumple']}%\n")

        lines.append(">> Estadística por familias de controles:")
        for g in group_stats:
            lines.append(f"   * {g['familia']:10s} (total {g['total']} controles): "
                         f"cumple {g['cumple']}%, parcial {g['parcial']}%, no cumple {g['no_cumple']}%")
        lines.append("")

        lines.append(">> Detalle de cada control:")
        for r in respuestas:
            estado = ""
            if r['respuesta'] == 'cumple':
                estado = "Cumple completamente"
            elif r['respuesta'] == 'parcial' and r['porcentaje'] is not None:
                estado = f"Cumple parcialmente ({r['porcentaje']}%)"
            else:
                estado = "No cumple"
            lines.append(f"   - {r['codigo']}: {estado}")

        return "\n".join(lines) + "\n"
