#!/usr/bin/env python3
"""
Genera reporte ejecutivo para el Director del ISAP a partir de los CSVs
exportados de la base de datos de producción.

Uso:
    python3 generar_reporte.py [ruta_carpeta_export]

Si no se indica la carpeta, busca automáticamente la más reciente
que empiece con 'export_bd_' en el directorio del script.
"""

import base64
import csv
import glob
import os
import sys
from collections import Counter, defaultdict
from datetime import datetime

# ── Rutas ──────────────────────────────────────────────────────────────────────
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
LOGO_PATH  = os.path.join(SCRIPT_DIR, "assets", "img", "logo.png")


# ── Carga de datos ─────────────────────────────────────────────────────────────
def load_csv(path):
    with open(path, newline="", encoding="utf-8-sig") as f:
        return list(csv.DictReader(f))


def find_export_dir(hint=None):
    if hint:
        return hint
    dirs = sorted(
        [p for p in glob.glob(os.path.join(SCRIPT_DIR, "export_bd_*")) if os.path.isdir(p)],
        reverse=True,
    )
    if not dirs:
        raise FileNotFoundError("No se encontró ninguna carpeta export_bd_* en el proyecto.")
    return dirs[0]


# ── Análisis ───────────────────────────────────────────────────────────────────
def analizar_usuarios(rows):
    alumnos    = [u for u in rows if u["rol"] == "ALUMNO"   and u["is_active"] == "1"]
    academicos = [u for u in rows if u["rol"] == "ACADEMICO" and u["is_active"] == "1"]

    por_programa = Counter(u["plan_de_estudio"] for u in alumnos if u["plan_de_estudio"])
    por_gen_raw  = Counter(u["generacion"] for u in alumnos if u["generacion"])
    # ordenar generaciones numéricamente
    por_gen = dict(sorted(por_gen_raw.items(), key=lambda x: int(x[0]) if x[0].isdigit() else 0))

    return {
        "total_alumnos":    len(alumnos),
        "total_academicos": len(academicos),
        "total_usuarios":   len(rows),
        "por_programa":     dict(por_programa),
        "por_generacion":   por_gen,
        "alumnos_list":     alumnos,
        "academicos_list":  academicos,
    }


ESTADO_LABEL = {
    "NOMBRAMIENTO":    "Nombramiento de Director",
    "TEMA":            "Definición del Tema de Tesis",
    "VOTO_DIR":        "Voto Aprobatorio del Director",
    "VOTO_LEC":        "Voto Aprobatorio de los Lectores",
    "EXAMEN_PENDIENTE":"Definición de Fecha de Examen",
    "EXAMEN_PROCESO":  "Examen en Proceso",
    "FINALIZADO":      "Examen Presentado y Aprobado",
}

ESTADO_NEXT = {
    "NOMBRAMIENTO":    "Asignar director de tesis",
    "TEMA":            "Confirmar tema y nombrar lectores",
    "VOTO_DIR":        "Esperar voto aprobatorio del director",
    "VOTO_LEC":        "Esperar votos de los lectores",
    "EXAMEN_PENDIENTE":"Programar fecha de examen de grado",
    "EXAMEN_PROCESO":  "Capturar veredicto del jurado",
    "FINALIZADO":      "Proceso concluido",
}

VEREDICTO_LABEL = {
    "UNANIME":     "Por unanimidad",
    "MAYORIA":     "Por mayoría",
    "NO_APROBADO": "No aprobado",
    "":            "—",
}


def analizar_tesis(tesis_rows, usuarios):
    id_to_user = {u["id"]: u for u in usuarios}

    def nombre(uid):
        u = id_to_user.get(uid, {})
        return f"{u.get('first_name','')} {u.get('last_name','')}".strip() or uid

    por_estado = Counter(t["estado"] for t in tesis_rows)

    finalizadas = []
    en_proceso  = []

    for t in tesis_rows:
        alumno_nombre = nombre(t["alumno_id"])
        titulo = t["titulo"] or "Sin título"
        estado = t["estado"]

        if estado == "FINALIZADO":
            finalizadas.append({
                "alumno":    alumno_nombre,
                "titulo":    titulo,
                "estado":    ESTADO_LABEL.get(estado, estado),
                "veredicto": VEREDICTO_LABEL.get(t.get("veredicto",""), t.get("veredicto","")),
                "fecha":     t.get("fecha_examen","")[:10] if t.get("fecha_examen") else "—",
                "director":  nombre(t.get("director_id","")),
            })
        else:
            en_proceso.append({
                "alumno":    alumno_nombre,
                "titulo":    titulo,
                "estado":    ESTADO_LABEL.get(estado, estado),
                "siguiente": ESTADO_NEXT.get(estado, "—"),
                "director":  nombre(t.get("director_id","")),
            })

    return {
        "total":       len(tesis_rows),
        "por_estado":  {ESTADO_LABEL.get(k,k): v for k, v in por_estado.items()},
        "finalizadas": finalizadas,
        "en_proceso":  en_proceso,
    }


ACTION_LABEL = {"1": "Creó", "2": "Modificó", "3": "Eliminó"}


def analizar_logs(rows, usuarios):
    id_to_user = {u["id"]: u for u in usuarios}

    def nombre(uid):
        u = id_to_user.get(uid, {})
        fn, ln = u.get("first_name",""), u.get("last_name","")
        uname  = u.get("username","")
        return f"{fn} {ln}".strip() or uname or uid

    filtered = [
        r for r in rows
        if id_to_user.get(r.get("user_id", ""), {}).get("username", "") != "admin_tec"
    ]
    recent = sorted(filtered, key=lambda x: x["action_time"], reverse=True)[:10]
    result = []
    for r in recent:
        result.append({
            "fecha":  r["action_time"][:16].replace("T", " "),
            "accion": ACTION_LABEL.get(r["action_flag"], r["action_flag"]),
            "objeto": r["object_repr"],
            "usuario": nombre(r.get("user_id","")),
        })
    return result


# ── Logo base64 ────────────────────────────────────────────────────────────────
def logo_b64():
    if os.path.exists(LOGO_PATH):
        with open(LOGO_PATH, "rb") as f:
            return base64.b64encode(f.read()).decode()
    return ""


# ── Render HTML ────────────────────────────────────────────────────────────────
def js_list(d):
    """Convierte dict → listas JS para Chart.js"""
    labels = list(d.keys())
    values = list(d.values())
    return labels, values


COLORES_DONA = ["#003366", "#a68942", "#4a7fc1", "#d4a843", "#1a4d8f", "#c49a2c"]
COLORES_BAR  = ["#a68942"] * 50   # dorado para barras de programa

ESTADO_BADGE_CSS = {
    "Nombramiento de Director":          "badge-muted",
    "Definición del Tema de Tesis":      "badge-muted",
    "Voto Aprobatorio del Director":     "badge-purple",
    "Voto Aprobatorio de los Lectores":  "badge-info",
    "Definición de Fecha de Examen":     "badge-warn",
    "Examen en Proceso":                 "badge-orange",
    "Examen Presentado y Aprobado":      "badge-ok",
}
VEREDICTO_BADGE_CSS = {
    "Por unanimidad": "badge-ok",
    "Por mayoría":    "badge-info",
    "No aprobado":    "badge-err",
    "—":              "badge-muted",
}


def render_kpi(valor, etiqueta, icono):
    return f"""
    <div class="kpi-card">
      <div class="kpi-icon">{icono}</div>
      <div class="kpi-valor">{valor}</div>
      <div class="kpi-label">{etiqueta}</div>
    </div>"""


def render_tabla_finalizadas(rows):
    if not rows:
        return "<p class='empty'>No hay tesis finalizadas.</p>"
    filas = ""
    for r in rows:
        v_badge = VEREDICTO_BADGE_CSS.get(r["veredicto"], "badge-muted")
        e_badge = ESTADO_BADGE_CSS.get(r["estado"], "badge-muted")
        filas += f"""
        <tr>
          <td>{r['alumno']}</td>
          <td class="titulo-col">{r['titulo']}</td>
          <td>{r['director']}</td>
          <td><span class="badge {e_badge}">{r['estado']}</span></td>
          <td><span class="badge {v_badge}">{r['veredicto']}</span></td>
          <td>{r['fecha']}</td>
        </tr>"""
    return f"""
    <table class="tabla">
      <thead><tr>
        <th>Alumno/a</th><th>Título</th><th>Director/a</th>
        <th>Estado</th><th>Veredicto</th><th>Fecha examen</th>
      </tr></thead>
      <tbody>{filas}</tbody>
    </table>"""


def render_tabla_proceso(rows):
    if not rows:
        return "<p class='empty'>No hay tesis en proceso.</p>"
    filas = ""
    for r in rows:
        badge = ESTADO_BADGE_CSS.get(r["estado"], "badge-muted")
        filas += f"""
        <tr>
          <td>{r['alumno']}</td>
          <td class="titulo-col">{r['titulo']}</td>
          <td>{r['director'] or '—'}</td>
          <td><span class="badge {badge}">{r['estado']}</span></td>
          <td>{r['siguiente']}</td>
        </tr>"""
    return f"""
    <table class="tabla">
      <thead><tr>
        <th>Alumno/a</th><th>Título</th><th>Director/a</th>
        <th>Estado</th><th>Siguiente paso</th>
      </tr></thead>
      <tbody>{filas}</tbody>
    </table>"""


def render_actividad(rows):
    if not rows:
        return "<p class='empty'>Sin actividad registrada.</p>"
    items = ""
    for r in rows:
        items += f"""
        <div class="timeline-item">
          <div class="tl-dot"></div>
          <div class="tl-body">
            <span class="tl-fecha">{r['fecha']}</span>
            <span class="tl-texto"><strong>{r['usuario']}</strong> {r['accion'].lower()} <em>{r['objeto']}</em></span>
          </div>
        </div>"""
    return f'<div class="timeline">{items}</div>'


def render_html(stats, export_dir_name):
    u  = stats["usuarios"]
    t  = stats["tesis"]
    logs = stats["logs"]
    logo = stats["logo"]
    now  = datetime.now().strftime("%d de %B de %Y, %H:%M hrs")

    # KPIs
    kpis = (
        render_kpi(u["total_alumnos"],    "Alumnos activos",    "🎓") +
        render_kpi(u["total_academicos"], "Académicos activos", "👨‍🏫") +
        render_kpi(len(t["finalizadas"]), "Tesis finalizadas",  "✅") +
        render_kpi(len(t["en_proceso"]),  "Tesis en proceso",   "📋")
    )

    # Datos Chart.js — estados tesis
    est_labels, est_vals = js_list(t["por_estado"])
    est_colors = COLORES_DONA[:len(est_labels)]

    # Datos Chart.js — alumnos por programa
    prog_labels, prog_vals = js_list(u["por_programa"])

    # Datos Chart.js — alumnos por generación
    gen_labels, gen_vals = js_list(u["por_generacion"])

    logo_tag = (
        f'<img src="data:image/png;base64,{logo}" class="logo" alt="Logo ISAP">'
        if logo else
        '<div class="logo-placeholder">ISAP</div>'
    )

    html = f"""<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Reporte Ejecutivo — ISAP Posgrados</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0/dist/chartjs-plugin-datalabels.min.js"></script>
<style>
  /* ── Reset y base ── */
  *, *::before, *::after {{ box-sizing: border-box; margin: 0; padding: 0; }}
  body {{
    font-family: 'Segoe UI', system-ui, sans-serif;
    background: #f0f2f5;
    color: #1f2937;
    font-size: 14px;
    line-height: 1.5;
  }}

  /* ── Header ── */
  .header {{
    background: #003366;
    color: #fff;
    padding: 24px 40px;
    display: flex;
    align-items: center;
    gap: 24px;
    border-bottom: 4px solid #a68942;
  }}
  .logo {{ height: 72px; width: auto; }}
  .logo-placeholder {{
    height: 72px; width: 120px;
    background: #a68942;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.4rem; font-weight: 700; color: #fff; border-radius: 4px;
  }}
  .header-text h1 {{
    font-size: 1.25rem; font-weight: 700; letter-spacing: .3px;
  }}
  .header-text p {{ font-size: .85rem; opacity: .8; margin-top: 2px; }}
  .header-meta {{
    margin-left: auto; text-align: right; font-size: .8rem; opacity: .75;
  }}
  .header-meta strong {{ display: block; font-size: .9rem; opacity: 1; }}

  /* ── Layout principal ── */
  .container {{ max-width: 1280px; margin: 0 auto; padding: 28px 24px; }}

  /* ── Sección ── */
  .section {{ margin-bottom: 32px; }}
  .section-title {{
    font-size: 1rem; font-weight: 700; color: #003366;
    border-left: 4px solid #a68942;
    padding-left: 10px; margin-bottom: 16px;
    text-transform: uppercase; letter-spacing: .5px;
  }}

  /* ── KPI cards ── */
  .kpi-grid {{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin-bottom: 32px;
  }}
  .kpi-card {{
    background: #fff;
    border-radius: 10px;
    padding: 22px 20px;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
    border-top: 4px solid #003366;
    display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  }}
  .kpi-icon {{ font-size: 1.8rem; }}
  .kpi-valor {{
    font-size: 2.4rem; font-weight: 800; color: #003366; line-height: 1;
  }}
  .kpi-label {{ font-size: .8rem; color: #6b7280; font-weight: 500; }}

  /* ── Charts grid ── */
  .charts-grid {{
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-bottom: 20px;
  }}
  .chart-card {{
    background: #fff;
    border-radius: 10px;
    padding: 20px;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
  }}
  .chart-card h3 {{
    font-size: .85rem; font-weight: 700; color: #003366;
    margin-bottom: 16px; text-transform: uppercase; letter-spacing: .3px;
  }}
  .chart-card canvas {{ max-height: 260px; }}
  .chart-wide {{ grid-column: 1 / -1; }}
  .chart-wide canvas {{ max-height: 180px; }}

  /* ── Tablas ── */
  .tabla-wrapper {{
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
    overflow: hidden;
    margin-bottom: 20px;
  }}
  .tabla {{
    width: 100%; border-collapse: collapse; font-size: .85rem;
  }}
  .tabla thead tr {{
    background: #003366; color: #fff;
  }}
  .tabla th {{
    padding: 11px 14px; text-align: left; font-weight: 600;
    font-size: .78rem; letter-spacing: .3px; text-transform: uppercase;
  }}
  .tabla td {{ padding: 10px 14px; border-bottom: 1px solid #e5e7eb; }}
  .tabla tbody tr:last-child td {{ border-bottom: none; }}
  .titulo-col {{ word-break: break-word; }}

  /* ── Badges ── */
  .badge {{
    display: inline-block; padding: 2px 9px;
    border-radius: 20px; font-size: .75rem; font-weight: 600;
  }}
  .badge-ok     {{ background: #d1fae5; color: #065f46; }}
  .badge-warn   {{ background: #fef3c7; color: #92400e; }}
  .badge-info   {{ background: #dbeafe; color: #1e40af; }}
  .badge-muted  {{ background: #f3f4f6; color: #374151; }}
  .badge-err    {{ background: #fee2e2; color: #991b1b; }}
  .badge-purple {{ background: #ede9fe; color: #5b21b6; }}
  .badge-orange {{ background: #ffedd5; color: #9a3412; }}

  /* ── Timeline actividad ── */
  .timeline {{ display: flex; flex-direction: column; gap: 0; }}
  .timeline-item {{
    display: flex; align-items: flex-start; gap: 14px;
    padding: 10px 20px;
    border-bottom: 1px solid #f3f4f6;
  }}
  .timeline-item:last-child {{ border-bottom: none; }}
  .tl-dot {{
    width: 10px; height: 10px; border-radius: 50%;
    background: #a68942; flex-shrink: 0; margin-top: 5px;
  }}
  .tl-body {{ flex: 1; }}
  .tl-fecha {{ font-size: .75rem; color: #9ca3af; margin-right: 8px; }}
  .tl-texto {{ font-size: .85rem; }}

  /* ── Footer ── */
  .footer {{
    background: #003366;
    color: rgba(255,255,255,.7);
    text-align: center;
    padding: 16px;
    font-size: .78rem;
    border-top: 3px solid #a68942;
    margin-top: 20px;
  }}
  .footer strong {{ color: #a68942; }}

  .empty {{ color: #9ca3af; font-style: italic; padding: 12px 0; }}

  /* ── Print ── */
  @media print {{
    @page {{ size: A4 landscape; margin: 12mm 14mm; }}
    body {{ background: #fff; font-size: 11px; }}
    .header {{ padding: 12px 20px; print-color-adjust: exact; -webkit-print-color-adjust: exact; }}
    .logo {{ height: 52px; }}
    .container {{ padding: 14px 0; }}
    .kpi-card, .chart-card, .tabla-wrapper {{
      box-shadow: none;
      border: 1px solid #ccd0d8;
      break-inside: avoid;
    }}
    .kpi-grid {{ gap: 10px; }}
    .kpi-valor {{ font-size: 1.8rem; }}
    .charts-grid {{ gap: 12px; }}
    .section {{ margin-bottom: 18px; }}
    .tabla th, .tabla td {{ padding: 7px 10px; }}
    .badge, .badge-ok, .badge-warn, .badge-info, .badge-muted,
    .badge-err, .badge-purple, .badge-orange {{
      print-color-adjust: exact; -webkit-print-color-adjust: exact;
    }}
    .tabla thead tr {{ print-color-adjust: exact; -webkit-print-color-adjust: exact; }}
    .footer {{
      position: fixed; bottom: 0; left: 0; right: 0;
      print-color-adjust: exact; -webkit-print-color-adjust: exact;
    }}
    .timeline-item {{ padding: 7px 14px; }}
  }}
</style>
</head>
<body>

<!-- HEADER -->
<header class="header">
  {logo_tag}
  <div class="header-text">
    <h1>Instituto Sonorense de Administración Pública</h1>
    <p>Sistema de Gestión de Posgrados — Reporte Ejecutivo</p>
  </div>
  <div class="header-meta">
    <strong>Dirección de Tecnologías</strong>
    {now}
  </div>
</header>

<div class="container">

  <!-- KPIs -->
  <div class="kpi-grid">
    {kpis}
  </div>

  <!-- GRÁFICAS: dona + barras programa -->
  <div class="section">
    <div class="section-title">Panorama académico</div>
    <div class="charts-grid">

      <div class="chart-card">
        <h3>Tesis por estado</h3>
        <canvas id="chartEstados"></canvas>
      </div>

      <div class="chart-card">
        <h3>Alumnos por programa</h3>
        <canvas id="chartPrograma"></canvas>
      </div>

      <div class="chart-card chart-wide">
        <h3>Alumnos por generación</h3>
        <canvas id="chartGeneracion"></canvas>
      </div>

    </div>
  </div>

  <!-- TESIS FINALIZADAS -->
  <div class="section">
    <div class="section-title">Tesis finalizadas ({len(t["finalizadas"])})</div>
    <div class="tabla-wrapper">
      {render_tabla_finalizadas(t["finalizadas"])}
    </div>
  </div>

  <!-- TESIS EN PROCESO -->
  <div class="section">
    <div class="section-title">Tesis en proceso ({len(t["en_proceso"])})</div>
    <div class="tabla-wrapper">
      {render_tabla_proceso(t["en_proceso"])}
    </div>
  </div>

  <!-- ACTIVIDAD RECIENTE -->
  <div class="section">
    <div class="section-title">Actividad reciente en el sistema</div>
    <div class="tabla-wrapper">
      {render_actividad(logs)}
    </div>
  </div>

</div><!-- /container -->

<footer class="footer">
  <strong>ISAP — Instituto Sonorense de Administración Pública</strong> &nbsp;|&nbsp;
  Sistema de Gestión de Posgrados &nbsp;|&nbsp;
  Generado automáticamente el {now} &nbsp;|&nbsp;
  Fuente: {export_dir_name}
</footer>

<script>
Chart.register(ChartDataLabels);

// ── Gráfica dona: estados de tesis
new Chart(document.getElementById('chartEstados'), {{
  type: 'doughnut',
  data: {{
    labels: {est_labels},
    datasets: [{{
      data: {est_vals},
      backgroundColor: {est_colors},
      borderWidth: 2, borderColor: '#fff'
    }}]
  }},
  options: {{
    plugins: {{
      legend: {{ position: 'right', labels: {{ font: {{ size: 12 }} }} }},
      tooltip: {{ enabled: false }},
      datalabels: {{
        color: '#fff',
        font: {{ weight: 'bold', size: 14 }},
        formatter: function(value, ctx) {{
          var total = ctx.chart.data.datasets[0].data.reduce((a,b) => a+b, 0);
          return value + ' (' + Math.round(value/total*100) + '%)';
        }}
      }}
    }},
    cutout: '55%'
  }}
}});

// ── Gráfica barras: alumnos por programa
new Chart(document.getElementById('chartPrograma'), {{
  type: 'bar',
  data: {{
    labels: {prog_labels},
    datasets: [{{
      label: 'Alumnos',
      data: {prog_vals},
      backgroundColor: '#003366',
      borderRadius: 6
    }}]
  }},
  options: {{
    plugins: {{
      legend: {{ display: false }},
      tooltip: {{ enabled: false }},
      datalabels: {{
        anchor: 'end', align: 'end',
        color: '#003366', font: {{ weight: 'bold', size: 13 }},
        formatter: function(v) {{ return v; }}
      }}
    }},
    scales: {{
      y: {{ beginAtZero: true, ticks: {{ stepSize: 1 }}, max: Math.max(...{prog_vals}) + 2 }},
      x: {{ grid: {{ display: false }} }}
    }}
  }}
}});

// ── Gráfica barras: alumnos por generación
new Chart(document.getElementById('chartGeneracion'), {{
  type: 'bar',
  data: {{
    labels: {gen_labels},
    datasets: [{{
      label: 'Alumnos',
      data: {gen_vals},
      backgroundColor: '#a68942',
      borderRadius: 4
    }}]
  }},
  options: {{
    indexAxis: 'x',
    plugins: {{
      legend: {{ display: false }},
      tooltip: {{ enabled: false }},
      datalabels: {{
        anchor: 'end', align: 'end',
        color: '#7a6030', font: {{ weight: 'bold', size: 11 }},
        formatter: function(v) {{ return v; }}
      }}
    }},
    scales: {{
      y: {{ beginAtZero: true, ticks: {{ stepSize: 1 }}, max: Math.max(...{gen_vals}) + 1 }},
      x: {{ grid: {{ display: false }}, ticks: {{ font: {{ size: 10 }} }} }}
    }}
  }}
}});
</script>
</body>
</html>"""
    return html


# ── Main ───────────────────────────────────────────────────────────────────────
def main():
    hint = sys.argv[1] if len(sys.argv) > 1 else None
    export_dir = find_export_dir(hint)
    print(f"Leyendo datos desde: {export_dir}")

    tesis_rows   = load_csv(os.path.join(export_dir, "tramites_tesis.csv"))
    usuario_rows = load_csv(os.path.join(export_dir, "tramites_usuario.csv"))
    log_rows     = load_csv(os.path.join(export_dir, "django_admin_log.csv"))

    u_stats = analizar_usuarios(usuario_rows)
    t_stats = analizar_tesis(tesis_rows, usuario_rows)
    logs    = analizar_logs(log_rows, usuario_rows)
    logo    = logo_b64()

    stats = {
        "usuarios": u_stats,
        "tesis":    t_stats,
        "logs":     logs,
        "logo":     logo,
    }

    html = render_html(stats, os.path.basename(export_dir))

    fecha   = datetime.now().strftime("%Y%m%d")
    outfile = os.path.join(SCRIPT_DIR, f"reporte_director_{fecha}.html")
    with open(outfile, "w", encoding="utf-8") as f:
        f.write(html)

    print(f"Reporte generado: {outfile}")


if __name__ == "__main__":
    main()
