#!/usr/bin/env python3
"""
Generador del Reporte Académico .docx — Semana 8 Visión por Computador (NRC-8773)
==================================================================================
Genera: Oviedo_Alexander_Reporte_RGA_S8_VC.docx

Formato: APA 7ª edición (Calibri 11pt, interlineado doble, márgenes 2.54 cm)
Extensión: 10-15 cuartillas
"""

import os
import sys

# Verificar dependencia
try:
    from docx import Document
    from docx.shared import Inches, Pt, Cm, RGBColor
    from docx.enum.text import WD_ALIGN_PARAGRAPH
    from docx.enum.table import WD_TABLE_ALIGNMENT
    from docx.enum.section import WD_ORIENT
    from docx.oxml.ns import qn
    from docx.oxml import OxmlElement
except ImportError:
    print("Instalando python-docx...")
    os.system(f"{sys.executable} -m pip install python-docx")
    from docx import Document
    from docx.shared import Inches, Pt, Cm, RGBColor
    from docx.enum.text import WD_ALIGN_PARAGRAPH
    from docx.enum.table import WD_TABLE_ALIGNMENT
    from docx.enum.section import WD_ORIENT
    from docx.oxml.ns import qn
    from docx.oxml import OxmlElement


# ─── Constantes APA 7 ─────────────────────────────────────────────────
FONT_NAME = "Calibri"
FONT_SIZE = Pt(11)
LINE_SPACING = 2.0
MARGIN = Cm(2.54)
INDENT = Cm(1.27)

# Colores institucionales
COLOR_TITULO = RGBColor(0x0B, 0x13, 0x2B)  # Azul oscuro
COLOR_SUBTITULO = RGBColor(0x1A, 0x5F, 0x7A)  # Azul medio
COLOR_TEXTO = RGBColor(0x33, 0x33, 0x33)  # Gris oscuro
COLOR_TABLA_HEADER = RGBColor(0x0B, 0x13, 0x2B)


# ─── Funciones auxiliares ──────────────────────────────────────────────

def set_cell_shading(cell, color_hex):
    """Aplica color de fondo a una celda de tabla."""
    shading = OxmlElement('w:shd')
    shading.set(qn('w:fill'), color_hex)
    shading.set(qn('w:val'), 'clear')
    cell._tc.get_or_add_tcPr().append(shading)


def format_paragraph(paragraph, font_size=FONT_SIZE, bold=False, italic=False,
                     alignment=WD_ALIGN_PARAGRAPH.LEFT, color=COLOR_TEXTO,
                     space_after=Pt(0), space_before=Pt(0), first_indent=None,
                     line_spacing=LINE_SPACING):
    """Formatea un párrafo completo según APA."""
    pf = paragraph.paragraph_format
    pf.alignment = alignment
    pf.space_after = space_after
    pf.space_before = space_before
    pf.line_spacing = line_spacing
    if first_indent is not None:
        pf.first_line_indent = first_indent

    for run in paragraph.runs:
        run.font.name = FONT_NAME
        run.font.size = font_size
        run.font.bold = bold
        run.font.italic = italic
        run.font.color.rgb = color


def add_paragraph_apa(doc, text, bold=False, italic=False,
                      alignment=WD_ALIGN_PARAGRAPH.LEFT,
                      indent=True, font_size=FONT_SIZE,
                      space_after=Pt(0)):
    """Agrega un párrafo con formato APA."""
    p = doc.add_paragraph()
    run = p.add_run(text)
    run.font.name = FONT_NAME
    run.font.size = font_size
    run.font.bold = bold
    run.font.italic = italic
    run.font.color.rgb = COLOR_TEXTO

    pf = p.paragraph_format
    pf.alignment = alignment
    pf.line_spacing = LINE_SPACING
    pf.space_after = space_after
    pf.space_before = Pt(0)
    if indent:
        pf.first_line_indent = INDENT
    return p


def add_heading_apa(doc, text, level=1):
    """Agrega un título con formato APA por niveles."""
    p = doc.add_paragraph()
    run = p.add_run(text)
    run.font.name = FONT_NAME
    run.font.color.rgb = COLOR_TITULO

    pf = p.paragraph_format
    pf.line_spacing = LINE_SPACING
    pf.space_before = Pt(12)
    pf.space_after = Pt(6)

    if level == 1:
        run.font.size = Pt(14)
        run.font.bold = True
        pf.alignment = WD_ALIGN_PARAGRAPH.CENTER
    elif level == 2:
        run.font.size = Pt(12)
        run.font.bold = True
        pf.alignment = WD_ALIGN_PARAGRAPH.LEFT
    elif level == 3:
        run.font.size = Pt(11)
        run.font.bold = True
        run.font.italic = True
        pf.alignment = WD_ALIGN_PARAGRAPH.LEFT
    return p


def add_table(doc, headers, rows, col_widths=None):
    """Agrega una tabla con formato APA."""
    table = doc.add_table(rows=1 + len(rows), cols=len(headers))
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    table.style = 'Table Grid'

    # Encabezados
    for i, header in enumerate(headers):
        cell = table.rows[0].cells[i]
        cell.text = header
        set_cell_shading(cell, '0B132B')
        for paragraph in cell.paragraphs:
            paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
            for run in paragraph.runs:
                run.font.name = FONT_NAME
                run.font.size = Pt(10)
                run.font.bold = True
                run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)

    # Filas de datos
    for r, row_data in enumerate(rows):
        for c, cell_text in enumerate(row_data):
            cell = table.rows[r + 1].cells[c]
            cell.text = str(cell_text)
            for paragraph in cell.paragraphs:
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                for run in paragraph.runs:
                    run.font.name = FONT_NAME
                    run.font.size = Pt(10)
                    run.font.color.rgb = COLOR_TEXTO

    if col_widths:
        for i, width in enumerate(col_widths):
            for row in table.rows:
                row.cells[i].width = width

    doc.add_paragraph()  # Espacio después de tabla
    return table


def add_reference(doc, text):
    """Agrega una referencia con sangría francesa."""
    p = doc.add_paragraph()
    run = p.add_run(text)
    run.font.name = FONT_NAME
    run.font.size = Pt(11)
    run.font.color.rgb = COLOR_TEXTO

    pf = p.paragraph_format
    pf.alignment = WD_ALIGN_PARAGRAPH.LEFT
    pf.line_spacing = LINE_SPACING
    pf.space_after = Pt(0)
    # Sangría francesa: left_indent + negative first_line_indent
    pf.left_indent = INDENT
    pf.first_line_indent = -INDENT
    return p


# ─── Construcción del Documento ───────────────────────────────────────

def build_document():
    doc = Document()

    # Configurar márgenes
    for section in doc.sections:
        section.top_margin = MARGIN
        section.bottom_margin = MARGIN
        section.left_margin = MARGIN
        section.right_margin = MARGIN

    # ═══════════════════════════════════════════════════════════════════
    # PORTADA
    # ═══════════════════════════════════════════════════════════════════

    # Espacios antes del título
    for _ in range(6):
        p = doc.add_paragraph()
        p.paragraph_format.line_spacing = LINE_SPACING

    # Título
    add_paragraph_apa(doc,
        "Reporte Académico: Diseño e Implementación de una "
        "Red Generativa Adversaria (DCGAN) para la Generación "
        "de Imágenes con CIFAR-10",
        bold=True, alignment=WD_ALIGN_PARAGRAPH.CENTER,
        indent=False, font_size=Pt(14))

    # Espacio
    doc.add_paragraph().paragraph_format.line_spacing = LINE_SPACING

    # Autores
    autores = [
        "Alexander Oviedo Fadul",
        "Maria Fernanda Ruiz Paipilla",
        "Neheman Samir Jaller Cerchiaro",
        "William David Obando Lopez",
        "Yesith Stiven Vizcano Mican"
    ]
    for autor in autores:
        add_paragraph_apa(doc, autor,
            alignment=WD_ALIGN_PARAGRAPH.CENTER, indent=False)

    # Espacio
    doc.add_paragraph().paragraph_format.line_spacing = LINE_SPACING

    # Datos institucionales
    datos = [
        "Grupo 10",
        "Especialización en Inteligencia Artificial",
        "Corporación Universitaria Minuto de Dios (UNIMINUTO)",
        "NRC-8773 — Visión por Computador — Semana 8",
        "Profesor: Félix Julián Gutiérrez Bernal",
        "Junio de 2026"
    ]
    for dato in datos:
        add_paragraph_apa(doc, dato,
            alignment=WD_ALIGN_PARAGRAPH.CENTER, indent=False)

    # Salto de página
    doc.add_page_break()

    # ═══════════════════════════════════════════════════════════════════
    # INTRODUCCIÓN
    # ═══════════════════════════════════════════════════════════════════

    add_heading_apa(doc, "Introducción", level=1)

    add_paragraph_apa(doc,
        "El presente reporte académico documenta el proceso de diseño e "
        "implementación de una Red Generativa Adversaria Convolucional Profunda "
        "(DCGAN, por sus siglas en inglés) desarrollada como actividad final del "
        "curso de Visión por Computador (NRC-8773). Esta actividad representa la "
        "culminación del recorrido formativo del periodo, integrando los "
        "conocimientos adquiridos a lo largo de las ocho semanas: desde el "
        "tratamiento básico de imágenes hasta las arquitecturas de redes "
        "neuronales convolucionales, pasando por la clasificación con CNN "
        "realizada en la Semana 7.")

    add_paragraph_apa(doc,
        "Las Redes Generativas Adversarias, propuestas originalmente por "
        "Goodfellow et al. (2014), constituyen uno de los avances más "
        "significativos en el campo del aprendizaje automático de la última "
        "década. Su capacidad para generar datos sintéticos realistas a partir "
        "de distribuciones aprendidas ha abierto posibilidades en ámbitos tan "
        "diversos como la generación de imágenes artísticas, la aumentación de "
        "datos para entrenamiento de modelos, la anonimización de información "
        "sensible y la simulación de escenarios para investigación científica.")

    add_paragraph_apa(doc,
        "El reporte se estructura en cuatro secciones principales. En primer "
        "lugar, se aborda el desarrollo teórico y práctico, dividido en una "
        "etapa de diseño — donde se describe la arquitectura de la red, el "
        "dataset empleado y las decisiones de ingeniería — y una etapa de "
        "implementación — donde se detallan las funciones de activación, los "
        "mecanismos de regularización y optimización, el flujo de datos y el "
        "código desarrollado. Posteriormente, se presentan los resultados "
        "obtenidos, incluyendo métricas de rendimiento y un collage de las "
        "imágenes generadas. Finalmente, se elaboran conclusiones sobre el "
        "alcance de los objetivos y la aplicabilidad profesional de esta "
        "tecnología.")

    add_paragraph_apa(doc,
        "El objetivo central de esta actividad es doble: por un lado, "
        "comprender la dinámica adversarial entre generador y discriminador "
        "que permite la síntesis de imágenes; por otro, desarrollar las "
        "competencias técnicas necesarias para implementar y evaluar este tipo "
        "de arquitecturas utilizando TensorFlow como framework principal, en "
        "línea con las herramientas trabajadas durante el curso.")

    # ═══════════════════════════════════════════════════════════════════
    # DESARROLLO
    # ═══════════════════════════════════════════════════════════════════

    add_heading_apa(doc, "Desarrollo", level=1)

    # --- Utilidad profesional ---
    add_heading_apa(doc,
        "Utilidad de las redes generativas adversarias en el desempeño "
        "profesional", level=2)

    add_paragraph_apa(doc,
        "Antes de adentrarnos en los aspectos técnicos, conviene reflexionar "
        "sobre la relevancia de las GANs en el contexto profesional de "
        "los integrantes del equipo. Como estudiantes de la Especialización en "
        "Inteligencia Artificial, la capacidad de generar datos sintéticos "
        "realistas tiene implicaciones directas en múltiples escenarios.")

    add_paragraph_apa(doc,
        "En el ámbito de la transformación digital del sector público, por "
        "ejemplo, uno de los desafíos recurrentes es la escasez de datos "
        "etiquetados para entrenar modelos de procesamiento automático de "
        "documentos. Las GANs ofrecen una solución elegante: generar documentos "
        "sintéticos que mantengan las características estadísticas de los reales "
        "sin comprometer la confidencialidad de la información ciudadana. "
        "A decir verdad, cuando empezamos a explorar esta posibilidad en el "
        "contexto del curso, nos dimos cuenta de que el potencial va más allá "
        "de lo que imaginábamos inicialmente.")

    add_paragraph_apa(doc,
        "En el sector salud, las GANs se han utilizado para generar imágenes "
        "médicas sintéticas (radiografías, resonancias magnéticas) que permiten "
        "entrenar sistemas de diagnóstico asistido sin violar regulaciones de "
        "privacidad del paciente. En el comercio electrónico, se emplean para "
        "crear variaciones de productos que aún no existen físicamente. Y en "
        "la investigación científica, como mencionó el profesor Félix Julián "
        "en la clase, se utilizan ampliamente para la simulación de fenómenos "
        "naturales y moléculas.")

    add_paragraph_apa(doc,
        "Sin embargo, también es necesario reconocer los dilemas éticos. "
        "Durante la sesión sincrónica, el profesor planteó una pregunta "
        "fundamental: ¿quién es el autor de una imagen generada por una red "
        "adversaria? Esta cuestión, que toca los derechos de propiedad "
        "intelectual, sigue abierta incluso en las legislaciones más avanzadas "
        "como la del Parlamento Europeo. Reconocemos que el uso responsable de "
        "estas tecnologías es tan importante como su dominio técnico.")

    # --- Preguntas orientadoras ---
    add_heading_apa(doc, "Preguntas orientadoras", level=2)

    add_heading_apa(doc,
        "¿Cómo evaluar la calidad de las imágenes generadas por una RGA?",
        level=3)

    add_paragraph_apa(doc,
        "La evaluación de la calidad de las imágenes generadas por una Red "
        "Generativa Adversaria es un problema complejo porque, a diferencia "
        "de la clasificación supervisada, no existe una métrica única y "
        "universalmente aceptada. En la práctica, se combinan enfoques "
        "cualitativos y cuantitativos.")

    add_paragraph_apa(doc,
        "Desde el punto de vista cualitativo, la inspección visual sigue "
        "siendo el primer filtro: ¿las imágenes generadas lucen coherentes? "
        "¿Presentan artefactos evidentes como texturas repetitivas, bordes "
        "irregulares o colores imposibles? ¿Existe diversidad en las muestras "
        "o todas se parecen entre sí (lo que indicaría mode collapse)?")

    add_paragraph_apa(doc,
        "Cuantitativamente, las métricas más utilizadas incluyen el FID "
        "(Fréchet Inception Distance), que mide la distancia entre las "
        "distribuciones de características de imágenes reales y generadas — "
        "valores más bajos indican mayor calidad —, y el IS (Inception Score), "
        "que evalúa tanto la calidad individual como la diversidad del "
        "conjunto generado. Además, el análisis de las curvas de pérdida "
        "durante el entrenamiento proporciona información sobre la estabilidad "
        "y convergencia del proceso adversarial (Dadhich, 2018).")

    add_heading_apa(doc,
        "¿Cuáles son los principales desafíos en la implementación de una RGA?",
        level=3)

    add_paragraph_apa(doc,
        "Los desafíos son tanto teóricos como prácticos. El más conocido es la "
        "inestabilidad del entrenamiento: dado que generador y discriminador "
        "compiten entre sí, lograr un equilibrio adecuado es delicado. Si el "
        "discriminador se vuelve demasiado fuerte, el generador no recibe "
        "gradientes útiles para mejorar; si el generador domina, el "
        "discriminador no puede distinguir imágenes reales de falsas, "
        "perdiendo su utilidad como señal de entrenamiento.")

    add_paragraph_apa(doc,
        "Otro desafío significativo es el mode collapse, donde el generador "
        "aprende a producir un conjunto limitado de imágenes que engañan al "
        "discriminador, sacrificando la diversidad. Esto es particularmente "
        "problemático en datasets como CIFAR-10, donde las diez clases "
        "requieren que la red capture una gran variedad de patrones visuales. "
        "Finalmente, el costo computacional es un factor que no puede "
        "subestimarse: como señaló el profesor en la clase de esta semana, "
        "la arquitectura, número de capas y demás tienen que ir creciendo "
        "conforme se busca mayor resolución y realismo en las imágenes "
        "generadas (Zafar, 2018).")

    # --- Etapa de diseño ---
    add_heading_apa(doc, "Etapa de diseño", level=2)

    add_heading_apa(doc, "Dataset CIFAR-10", level=3)

    add_paragraph_apa(doc,
        "Para esta actividad, el equipo decidió utilizar el dataset CIFAR-10 "
        "como base de entrenamiento para la DCGAN, en continuidad con el "
        "trabajo de clasificación realizado en la Semana 7. CIFAR-10 es un "
        "dataset estándar de referencia en visión por computador que contiene "
        "60,000 imágenes a color (32×32 píxeles, 3 canales RGB) distribuidas "
        "uniformemente en 10 clases: avión, automóvil, pájaro, gato, ciervo, "
        "perro, rana, caballo, barco y camión.")

    add_table(doc,
        ["Característica", "Detalle"],
        [
            ["Nombre del dataset", "CIFAR-10 (Canadian Institute for Advanced Research)"],
            ["Imágenes totales", "60,000 (50,000 train + 10,000 test)"],
            ["Resolución", "32 × 32 píxeles"],
            ["Canales de color", "3 (RGB)"],
            ["Número de clases", "10"],
            ["Normalización aplicada", "[-1, 1] (para compatibilidad con tanh)"],
            ["Formato de píxeles original", "uint8 [0, 255]"],
        ])

    add_paragraph_apa(doc,
        "La elección de CIFAR-10 sobre MNIST (el dataset utilizado en los "
        "notebooks de referencia del Drive) responde a dos razones. Primero, "
        "la continuidad con el proyecto de la Semana 7, donde ya habíamos "
        "construido y entrenado una CNN clasificadora con este mismo dataset. "
        "Segundo, el desafío adicional que supone trabajar con imágenes a "
        "color de objetos reales, en contraste con los dígitos en escala de "
        "grises de MNIST. Reconocemos que esto hace el problema más difícil, "
        "pero también más representativo de aplicaciones del mundo real.")

    add_heading_apa(doc, "Arquitectura DCGAN", level=3)

    add_paragraph_apa(doc,
        "La Deep Convolutional Generative Adversarial Network (DCGAN), "
        "propuesta por Radford et al. (2016), es una extensión de la GAN "
        "original que introduce operaciones convolucionales en ambas redes. "
        "A diferencia de la GAN básica que opera exclusivamente con capas "
        "densas (fully connected), la DCGAN aprovecha la estructura espacial "
        "de las imágenes mediante convoluciones, lo que le permite capturar "
        "patrones locales como bordes, texturas y formas.")

    add_paragraph_apa(doc,
        "Nuestra implementación sigue las directrices arquitectónicas "
        "establecidas en el paper original de DCGAN, con las siguientes "
        "adaptaciones para CIFAR-10:")

    add_table(doc,
        ["Principio DCGAN", "Implementación"],
        [
            ["Reemplazar pooling por convoluciones con stride",
             "Conv2DTranspose con stride=2 en G, Conv2D con stride=2 en D"],
            ["Usar BatchNormalization",
             "En todas las capas de G (excepto salida) y D (excepto entrada)"],
            ["Eliminar capas fully connected intermedias",
             "Solo una capa Dense inicial en G para proyección"],
            ["ReLU en el generador",
             "ReLU en capas internas, tanh en salida"],
            ["LeakyReLU en el discriminador",
             "LeakyReLU(α=0.2) en todas las capas"],
        ])

    add_heading_apa(doc, "Arquitectura del generador", level=3)

    add_paragraph_apa(doc,
        "El generador transforma un vector de ruido aleatorio z de dimensión "
        "100 (muestreado de una distribución normal estándar) en una imagen "
        "de 32×32×3 píxeles. El proceso de upsampling progresivo se realiza "
        "mediante convoluciones transpuestas (Conv2DTranspose) que duplican "
        "las dimensiones espaciales en cada paso:")

    add_table(doc,
        ["Capa", "Operación", "Salida", "Activación"],
        [
            ["Entrada", "Vector latente z", "(100,)", "—"],
            ["Dense + Reshape", "Dense(4×4×256) → Reshape", "(4, 4, 256)", "ReLU"],
            ["ConvTranspose 1", "128 filtros, 5×5, stride=2", "(8, 8, 128)", "ReLU"],
            ["ConvTranspose 2", "64 filtros, 5×5, stride=2", "(16, 16, 64)", "ReLU"],
            ["ConvTranspose 3", "3 filtros, 5×5, stride=2", "(32, 32, 3)", "tanh"],
        ])

    add_paragraph_apa(doc,
        "La función de activación tanh en la capa de salida produce valores "
        "en el rango [-1, 1], que es compatible con la normalización aplicada "
        "al dataset de entrenamiento. Todas las capas convolucionales se "
        "configuran sin bias (use_bias=False), ya que la BatchNormalization "
        "posterior hace redundante el término de sesgo.")

    add_heading_apa(doc, "Arquitectura del discriminador", level=3)

    add_paragraph_apa(doc,
        "El discriminador funciona como una CNN clasificadora binaria que "
        "recibe una imagen de 32×32×3 y produce una probabilidad de que la "
        "imagen sea real (proveniente del dataset) o falsa (generada por G). "
        "Estructuralmente, es el espejo del generador, realizando downsampling "
        "mediante convoluciones con stride:")

    add_table(doc,
        ["Capa", "Operación", "Salida", "Activación"],
        [
            ["Entrada", "Imagen RGB", "(32, 32, 3)", "—"],
            ["Conv2D 1", "64 filtros, 5×5, stride=2", "(16, 16, 64)", "LeakyReLU(0.2)"],
            ["Conv2D 2", "128 filtros, 5×5, stride=2", "(8, 8, 128)", "LeakyReLU(0.2)"],
            ["Flatten + Dense", "Flatten → Dense(1)", "(1,)", "Sigmoid"],
        ])

    add_paragraph_apa(doc,
        "Se utiliza LeakyReLU con pendiente negativa α=0.2 en lugar de ReLU "
        "estándar, lo cual permite gradientes negativos pequeños y evita el "
        "problema de neuronas muertas. Se aplica Dropout con probabilidad 0.3 "
        "después de cada LeakyReLU como mecanismo de regularización, evitando "
        "que el discriminador se vuelva demasiado fuerte demasiado rápido y "
        "ahogue al generador.")

    # --- Etapa de implementación ---
    add_heading_apa(doc, "Etapa de implementación", level=2)

    add_heading_apa(doc,
        "Funciones de activación empleadas", level=3)

    add_paragraph_apa(doc,
        "La selección de funciones de activación en una GAN es crítica y "
        "difiere entre el generador y el discriminador. A continuación se "
        "detallan las funciones utilizadas y su justificación:")

    add_table(doc,
        ["Función", "Ubicación", "Fórmula", "Justificación"],
        [
            ["ReLU", "G (capas internas)", "max(0, x)",
             "Permite gradientes fuertes, aprendizaje rápido"],
            ["tanh", "G (salida)", "(eˣ - e⁻ˣ)/(eˣ + e⁻ˣ)",
             "Rango [-1,1] compatible con normalización de datos"],
            ["LeakyReLU", "D (todas las capas)", "max(αx, x), α=0.2",
             "Evita neuronas muertas, gradientes negativos"],
            ["Sigmoid", "D (salida)", "1/(1 + e⁻ˣ)",
             "Probabilidad binaria (real vs. falso)"],
        ])

    add_heading_apa(doc,
        "Regularización y optimización", level=3)

    add_paragraph_apa(doc,
        "La regularización en una DCGAN tiene un objetivo diferente al de una "
        "CNN clasificadora convencional. Mientras en clasificación se busca "
        "prevenir el sobreajuste a los datos de entrenamiento, en una GAN la "
        "regularización busca estabilizar la dinámica adversarial y prevenir "
        "que una de las redes domine a la otra.")

    add_paragraph_apa(doc,
        "BatchNormalization se aplica en el generador después de cada capa "
        "convolucional transpuesta (excepto la de salida). Esta técnica "
        "normaliza las activaciones de cada mini-batch, reduciendo el "
        "problema de internal covariate shift y permitiendo tasas de "
        "aprendizaje más altas sin sacrificar estabilidad. En el "
        "discriminador, se utiliza Dropout con probabilidad p=0.3, que "
        "desactiva aleatoriamente el 30% de las neuronas durante el "
        "entrenamiento, actuando como un ensamble implícito que suaviza "
        "la superficie de decisión del discriminador.")

    add_paragraph_apa(doc,
        "Para la optimización, se emplea el algoritmo Adam (Kingma & Ba, "
        "2015) con hiperparámetros específicos para entrenamiento adversarial: "
        "tasa de aprendizaje de 1×10⁻⁴ y β₁=0.5 (en lugar del valor por "
        "defecto de 0.9). Estos valores provienen de las recomendaciones "
        "empíricas del paper original de DCGAN (Radford et al., 2016) y han "
        "demostrado proporcionar mayor estabilidad en el entrenamiento "
        "competitivo entre generador y discriminador.")

    add_table(doc,
        ["Hiperparámetro", "Valor", "Justificación"],
        [
            ["Learning rate", "1×10⁻⁴", "Recomendación DCGAN (Radford et al., 2016)"],
            ["β₁ (Adam)", "0.5", "Estabilidad en entrenamiento adversarial"],
            ["β₂ (Adam)", "0.999", "Valor estándar"],
            ["Épocas", "50", "Balance entre calidad y costo computacional"],
            ["Batch size", "128", "Estándar para DCGAN"],
            ["Dimensión latente", "100", "Espacio suficiente para diversidad"],
            ["Dropout (D)", "0.3", "Regularización del discriminador"],
        ])

    add_heading_apa(doc,
        "Flujo de datos dentro de la red", level=3)

    add_paragraph_apa(doc,
        "El flujo de datos en una DCGAN sigue un patrón cíclico durante el "
        "entrenamiento. En cada iteración (paso de entrenamiento), ocurren "
        "dos fases secuenciales:")

    add_paragraph_apa(doc,
        "Fase 1 — Entrenamiento del Discriminador: Se toma un mini-batch de "
        "imágenes reales del dataset CIFAR-10 y se le asigna la etiqueta 1 "
        "(real). Simultáneamente, se genera un mini-batch de imágenes falsas "
        "alimentando vectores de ruido aleatorio al generador, y se le asigna "
        "la etiqueta 0 (falso). El discriminador procesa ambos conjuntos y "
        "calcula la Binary Cross-Entropy combinada. Los gradientes se "
        "retropropagan únicamente a través del discriminador, actualizando "
        "sus pesos para mejorar su capacidad de discriminación.")

    add_paragraph_apa(doc,
        "Fase 2 — Entrenamiento del Generador: Se genera un nuevo mini-batch "
        "de imágenes falsas a partir de ruido aleatorio. Estas imágenes se "
        "pasan por el discriminador, pero esta vez se les asigna la etiqueta "
        "1 (intentamos engañar a D). La pérdida resultante indica qué tan "
        "lejos están las imágenes generadas de ser clasificadas como reales. "
        "Los gradientes se retropropagan a través del discriminador (congelado) "
        "hasta el generador, actualizando los pesos de G para que produzca "
        "imágenes más convincentes.")

    add_paragraph_apa(doc,
        "Este proceso iterativo, implementado con el decorador @tf.function "
        "de TensorFlow para eficiencia computacional, se repite durante 50 "
        "épocas completas sobre el dataset de entrenamiento. Como describió "
        "el profesor en clase, es un proceso donde el generador y el "
        "discriminador compiten basados en una métrica, y a medida que pasa "
        "el tiempo, los valores W se van ajustando hasta que la red logra "
        "generar imágenes reconocibles.")

    add_heading_apa(doc,
        "Descripción del código desarrollado", level=3)

    add_paragraph_apa(doc,
        "La implementación completa se desarrolló en un Jupyter Notebook "
        "utilizando Python 3 con TensorFlow/Keras como framework principal. "
        "Este notebook está publicado y disponible para su ejecución interactiva en "
        "Google Colab a través del siguiente enlace: "
        "https://colab.research.google.com/github/bladealex9848/UNIMINUTO/blob/main/2do%20CUATRIMESTRE/NRC-8773-Visi%C3%B3n%20por%20Computador/ACTIVIDADES/MA%20Semana%208/Oviedo_Alexander_DCGAN_RGA_S8_VC.ipynb. "
        "El código está estructurado en secciones bien diferenciadas que "
        "abarcan desde la carga del dataset hasta la generación final de "
        "imágenes. Los componentes principales del código incluyen:")

    add_paragraph_apa(doc,
        "La función build_generator() construye la red generadora como un "
        "modelo Sequential de Keras con capas Dense, Reshape, "
        "Conv2DTranspose, BatchNormalization y activaciones ReLU/tanh. La "
        "función build_discriminator() implementa la red discriminadora con "
        "capas Conv2D, LeakyReLU, Dropout y una capa Dense final con sigmoid. "
        "El paso de entrenamiento se encapsula en la función train_step(), "
        "decorada con @tf.function para compilación en grafo, que ejecuta "
        "secuencialmente el entrenamiento del discriminador y del generador "
        "utilizando GradientTape de TensorFlow para el cálculo automático "
        "de gradientes.")

    add_paragraph_apa(doc,
        "Para facilitar la reproducibilidad y la transparencia del proceso, "
        "el notebook incluye celdas de verificación que validan las formas de "
        "salida de ambas redes antes de iniciar el entrenamiento, así como "
        "funciones de visualización que generan grids de imágenes cada 10 "
        "épocas para monitorear el progreso. Todo el código está documentado "
        "con comentarios detallados y celdas markdown explicativas que "
        "contextualizan cada decisión técnica.")

    # ═══════════════════════════════════════════════════════════════════
    # RESULTADOS
    # ═══════════════════════════════════════════════════════════════════

    add_heading_apa(doc, "Resultados", level=1)

    add_paragraph_apa(doc,
        "Tras completar las 50 épocas de entrenamiento sobre las 50,000 "
        "imágenes de CIFAR-10, la DCGAN logró generar imágenes sintéticas "
        "que capturan patrones visuales generales del dataset, incluyendo "
        "paletas de color y formas geométricas básicas. A continuación se "
        "presentan los resultados obtenidos.")

    add_heading_apa(doc, "Curvas de pérdida", level=2)

    add_paragraph_apa(doc,
        "El análisis de las curvas de pérdida es el indicador principal de "
        "la dinámica del entrenamiento adversarial. En una DCGAN bien "
        "entrenada, se espera que las pérdidas del generador y del "
        "discriminador oscilen sin que ninguna se acerque permanentemente a "
        "cero, lo que indicaría que una red ha dominado completamente a la "
        "otra.")

    add_paragraph_apa(doc,
        "En nuestro caso, las pérdidas mostraron un comportamiento oscilante "
        "característico del entrenamiento adversarial. La pérdida del "
        "discriminador se mantuvo en un rango estable, mientras que la del "
        "generador fluctuó a medida que la red aprendía a producir imágenes "
        "cada vez más convincentes. Este patrón es consistente con lo "
        "reportado en la literatura para DCGAN entrenadas con datasets de "
        "baja resolución (Radford et al., 2016).")

    add_paragraph_apa(doc,
        "Nota: Las gráficas de las curvas de pérdida se encuentran "
        "generadas y visualizadas en el notebook Jupyter adjunto "
        "(Oviedo_Alexander_DCGAN_RGA_S8_VC.ipynb), sección 7.1.")

    add_heading_apa(doc, "Imágenes generadas", level=2)

    add_paragraph_apa(doc,
        "El resultado final del entrenamiento es un conjunto de 36 imágenes "
        "sintéticas (organizadas en un collage de 6×6) generadas a partir de "
        "vectores de ruido aleatorio. Estas imágenes no existen en el dataset "
        "original; son completamente nuevas, creadas por el generador después "
        "de aprender las distribuciones estadísticas de las imágenes reales "
        "de CIFAR-10.")

    add_paragraph_apa(doc,
        "La evolución temporal de las imágenes generadas permite observar "
        "el proceso de aprendizaje de la red: en las primeras épocas, las "
        "imágenes son esencialmente ruido aleatorio; hacia la época 10-20, "
        "comienzan a emerger patrones de color y formas geométricas básicas; "
        "y en las épocas finales, las imágenes presentan mayor coherencia "
        "visual con texturas y distribuciones de color que se asemejan a las "
        "del dataset de entrenamiento.")

    add_paragraph_apa(doc,
        "Es importante ser honestos sobre las limitaciones: a una resolución "
        "de 32×32 píxeles, las imágenes generadas no alcanzan un fotorrealismo "
        "comparable al de arquitecturas más avanzadas (como StyleGAN) que "
        "trabajan a resoluciones de 256×256 o superiores. Sin embargo, sí "
        "logran capturar las distribuciones de color, las formas generales y "
        "los patrones de textura del dataset, lo cual valida la correcta "
        "implementación del modelo.")

    add_paragraph_apa(doc,
        "Nota: El collage completo de las 36 imágenes generadas y la "
        "comparación visual entre imágenes reales y generadas se encuentran "
        "en el notebook adjunto, secciones 7.2, 7.3 y 7.4.")

    add_heading_apa(doc, "Resumen de métricas", level=2)

    add_table(doc,
        ["Métrica", "Valor"],
        [
            ["Dataset", "CIFAR-10 (32×32×3, RGB)"],
            ["Imágenes de entrenamiento", "50,000"],
            ["Épocas completadas", "50"],
            ["Imágenes generadas", "36 (collage 6×6)"],
            ["Framework", "TensorFlow / Keras"],
            ["Dimensión latente", "100"],
            ["Función de pérdida", "Binary Cross-Entropy"],
            ["Optimizador", "Adam (lr=1e-4, β₁=0.5)"],
        ])

    # ═══════════════════════════════════════════════════════════════════
    # CONCLUSIONES
    # ═══════════════════════════════════════════════════════════════════

    add_heading_apa(doc, "Conclusiones", level=1)

    add_paragraph_apa(doc,
        "El presente trabajo logró cumplir satisfactoriamente los objetivos "
        "propuestos para la actividad de la Semana 8. Se diseñó e implementó "
        "una Red Generativa Adversaria Convolucional Profunda (DCGAN) "
        "funcional, capaz de generar imágenes sintéticas a color de 32×32 "
        "píxeles a partir de vectores de ruido aleatorio. Se produjo un "
        "conjunto de 36 imágenes nuevas, superando el mínimo requerido de 30, "
        "y se documentó exhaustivamente el proceso en un notebook Jupyter "
        "reproducible.")

    add_paragraph_apa(doc,
        "Desde el punto de vista técnico, la experiencia de implementar una "
        "DCGAN desde cero — adaptando los notebooks de referencia del curso "
        "de MNIST a CIFAR-10 — nos permitió comprender en profundidad la "
        "dinámica adversarial entre generador y discriminador. Lo que al "
        "principio parecía un concepto abstracto (dos redes compitiendo "
        "entre sí) se volvió tangible cuando observamos cómo las imágenes "
        "evolucionaban de ruido puro a formas cada vez más reconocibles "
        "a medida que avanzaba el entrenamiento.")

    add_paragraph_apa(doc,
        "Reconocemos que la calidad de las imágenes generadas tiene "
        "limitaciones inherentes a la resolución del dataset (32×32 píxeles). "
        "Generar dígitos MNIST es relativamente sencillo porque son imágenes "
        "binarias simples; CIFAR-10, con sus objetos complejos a color, "
        "presenta un desafío significativamente mayor. Para futuras "
        "iteraciones, sería interesante explorar arquitecturas más avanzadas "
        "como StyleGAN o la incorporación de mecanismos de atención, así como "
        "experimentar con técnicas de entrenamiento progresivo que permitan "
        "generar imágenes a resoluciones más altas.")

    add_paragraph_apa(doc,
        "En cuanto a la aplicabilidad profesional, las redes generativas "
        "adversarias representan una herramienta con enorme potencial para "
        "la generación de datos sintéticos en contextos donde los datos reales "
        "son escasos, costosos o sensibles. En el ámbito de la inteligencia "
        "artificial aplicada, dominar estas técnicas abre posibilidades para "
        "la aumentación de datos de entrenamiento, la anonimización de "
        "información y la generación de escenarios de prueba. Como reflexión "
        "final, coincidimos con lo planteado por el profesor Félix Julián "
        "respecto a la importancia de considerar los aspectos éticos y legales "
        "del uso de estas tecnologías, especialmente en lo relacionado con "
        "los derechos de propiedad intelectual sobre el contenido generado.")

    # ═══════════════════════════════════════════════════════════════════
    # REFERENCIAS
    # ═══════════════════════════════════════════════════════════════════

    add_heading_apa(doc, "Referencias", level=1)

    referencias = [
        "Dadhich, A. (2018). Chapter 5: Convolutional Neural Networks. "
        "En Practical computer vision: Extract insightful information "
        "from images using TensorFlow, Keras, and OpenCV (pp. 88-125). "
        "Packt Publishing.",

        "Goodfellow, I. J., Pouget-Abadie, J., Mirza, M., Xu, B., "
        "Warde-Farley, D., Ozair, S., Courville, A., & Bengio, Y. (2014). "
        "Generative Adversarial Nets. Advances in Neural Information "
        "Processing Systems, 27, 2672-2680.",

        "Kingma, D. P., & Ba, J. (2015). Adam: A Method for Stochastic "
        "Optimization. Proceedings of the 3rd International Conference on "
        "Learning Representations (ICLR).",

        "Krizhevsky, A. (2009). Learning Multiple Layers of Features from "
        "Tiny Images [Tesis de maestría, University of Toronto]. "
        "Department of Computer Science.",

        "Radford, A., Metz, L., & Chintala, S. (2016). Unsupervised "
        "Representation Learning with Deep Convolutional Generative "
        "Adversarial Networks. Proceedings of the 4th International "
        "Conference on Learning Representations (ICLR).",

        "Zafar, I. (2018). Generative Adversarial Networks. En Hands-on "
        "convolutional neural networks with TensorFlow: Solve computer "
        "vision problems with modeling in TensorFlow and Python "
        "(pp. 172-188). Packt Publishing.",
    ]

    for ref in referencias:
        add_reference(doc, ref)

    return doc


# ─── Main ──────────────────────────────────────────────────────────────
if __name__ == "__main__":
    print("Generando reporte académico .docx...")
    print("  Formato: APA 7ª edición")
    print("  Fuente: Calibri 11pt")
    print("  Interlineado: Doble")
    print("  Márgenes: 2.54 cm")
    print()

    doc = build_document()

    output_dir = os.path.dirname(os.path.abspath(__file__))
    output_path = os.path.join(output_dir,
                               "Oviedo_Alexander_Reporte_RGA_S8_VC.docx")
    doc.save(output_path)

    print(f"✅ Documento generado: {output_path}")
    print(f"   Secciones: Portada, Introducción, Desarrollo, Resultados, "
          f"Conclusiones, Referencias")
