# Script para FreeCAD - Procesador de Documentos Word con Carátula
import os
import glob
from PySide2 import QtWidgets, QtCore
from PySide2.QtWidgets import (QFileDialog, QMessageBox, QProgressDialog,
                               QApplication, QVBoxLayout, QWidget, QPushButton,
                               QLabel, QTextEdit)
import FreeCAD
import FreeCADGui

import PVPlantResources
from PVPlantResources import DirIcons as DirIcons

try:
    from docx import Document
    from docx.shared import Pt, RGBColor, Inches
    from docx.enum.text import WD_ALIGN_PARAGRAPH
    from docx.oxml.ns import qn

    DOCX_AVAILABLE = True
except ImportError:
    DOCX_AVAILABLE = False
    FreeCAD.Console.PrintError("Error: python-docx no está instalado. Instala con: pip install python-docx\n")


class DocumentProcessor(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(DocumentProcessor, self).__init__(parent)
        self.caratula_path = ""
        self.carpeta_path = ""
        self.setup_ui()

    def setup_ui(self):
        self.setWindowTitle("Procesador de Documentos Word")
        self.setMinimumWidth(600)
        self.setMinimumHeight(500)

        layout = QVBoxLayout()

        # Título
        title = QLabel("<h2>Procesador de Documentos Word</h2>")
        title.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(title)

        # Información
        info_text = QLabel(
            "Este script buscará recursivamente todos los archivos .docx en una carpeta,\n"
            "insertará una carátula y aplicará formato estándar a todos los documentos."
        )
        info_text.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(info_text)

        # Botón seleccionar carátula
        self.btn_caratula = QPushButton("1. Seleccionar Carátula")
        self.btn_caratula.clicked.connect(self.seleccionar_caratula)
        layout.addWidget(self.btn_caratula)

        self.label_caratula = QLabel("No se ha seleccionado carátula")
        self.label_caratula.setWordWrap(True)
        layout.addWidget(self.label_caratula)

        # Botón seleccionar carpeta
        self.btn_carpeta = QPushButton("2. Seleccionar Carpeta de Documentos")
        self.btn_carpeta.clicked.connect(self.seleccionar_carpeta)
        layout.addWidget(self.btn_carpeta)

        self.label_carpeta = QLabel("No se ha seleccionado carpeta")
        self.label_carpeta.setWordWrap(True)
        layout.addWidget(self.label_carpeta)

        # Botón procesar
        self.btn_procesar = QPushButton("3. Procesar Documentos")
        self.btn_procesar.clicked.connect(self.procesar_documentos)
        self.btn_procesar.setEnabled(False)
        layout.addWidget(self.btn_procesar)

        # Área de log
        self.log_area = QTextEdit()
        self.log_area.setReadOnly(True)
        layout.addWidget(self.log_area)

        # Botón cerrar
        self.btn_cerrar = QPushButton("Cerrar")
        self.btn_cerrar.clicked.connect(self.close)
        layout.addWidget(self.btn_cerrar)

        self.setLayout(layout)

    def log(self, mensaje):
        """Agrega un mensaje al área de log"""
        self.log_area.append(mensaje)
        QApplication.processEvents()  # Para actualizar la UI

    def seleccionar_caratula(self):
        """Abre un diálogo para seleccionar el archivo de carátula"""
        archivo, _ = QFileDialog.getOpenFileName(
            self,
            "Seleccionar archivo de carátula",
            "",
            "Word documents (*.docx);;All files (*.*)"
        )

        if archivo and os.path.exists(archivo):
            self.caratula_path = archivo
            self.label_caratula.setText(f"Carátula: {os.path.basename(archivo)}")
            self.verificar_estado()
            self.log(f"✓ Carátula seleccionada: {archivo}")

    def seleccionar_carpeta(self):
        """Abre un diálogo para seleccionar la carpeta de documentos"""
        carpeta = QFileDialog.getExistingDirectory(
            self,
            "Seleccionar carpeta con documentos"
        )

        if carpeta:
            self.carpeta_path = carpeta
            self.label_carpeta.setText(f"Carpeta: {carpeta}")
            self.verificar_estado()
            self.log(f"✓ Carpeta seleccionada: {carpeta}")

    def verificar_estado(self):
        """Habilita el botón procesar si ambos paths están seleccionados"""
        if self.caratula_path and self.carpeta_path:
            self.btn_procesar.setEnabled(True)

    def buscar_docx_recursivamente(self, carpeta):
        """Busca recursivamente todos los archivos .docx en una carpeta"""
        archivos_docx = []
        patron = os.path.join(carpeta, "**", "*.docx")

        for archivo in glob.glob(patron, recursive=True):
            archivos_docx.append(archivo)

        return archivos_docx

    def aplicar_formato_estandar(self, doc):
        """Aplica formato estándar al documento"""
        try:
            # Configurar estilos por defecto
            style = doc.styles['Normal']
            font = style.font
            font.name = 'Arial'
            font.size = Pt(11)
            font.color.rgb = RGBColor(0, 0, 0)  # Negro

            # Configurar encabezados
            try:
                heading_style = doc.styles['Heading 1']
                heading_font = heading_style.font
                heading_font.name = 'Arial'
                heading_font.size = Pt(14)
                heading_font.bold = True
                heading_font.color.rgb = RGBColor(0, 51, 102)  # Azul oscuro
            except:
                pass

        except Exception as e:
            self.log(f"   ⚠ Advertencia en formato: {str(e)}")

    def aplicar_formato_avanzado(self, doc):
        """Aplica formato más avanzado y personalizado"""
        try:
            # Configurar márgenes
            sections = doc.sections
            for section in sections:
                section.top_margin = Inches(1)
                section.bottom_margin = Inches(1)
                section.left_margin = Inches(1)
                section.right_margin = Inches(1)

            # Configurar estilos de párrafo
            for paragraph in doc.paragraphs:
                paragraph.paragraph_format.space_after = Pt(6)
                paragraph.paragraph_format.space_before = Pt(0)
                paragraph.paragraph_format.line_spacing = 1.15

                # Alinear párrafos justificados
                paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

                # Aplicar fuente específica a cada run
                for run in paragraph.runs:
                    run.font.name = 'Arial'
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Arial')
                    run.font.size = Pt(11)

        except Exception as e:
            self.log(f"   ⚠ Advertencia en formato avanzado: {str(e)}")

    def insertar_caratula_y_formatear(self, archivo_docx, archivo_caratula):
        """Inserta la carátula y aplica formato al documento"""
        try:
            # Abrir el documento de carátula
            doc_caratula = Document(archivo_caratula)

            # Abrir el documento destino
            doc_destino = Document(archivo_docx)

            # Crear un nuevo documento que contendrá la carátula + contenido original
            nuevo_doc = Document()

            # Copiar todo el contenido de la carátula
            for elemento in doc_caratula.element.body:
                print(elemento)
                nuevo_doc.element.body.append(elemento)

            # Agregar un salto de página después de la carátula
            nuevo_doc.add_page_break()

            # Copiar todo el contenido del documento original
            for elemento in doc_destino.element.body:
                nuevo_doc.element.body.append(elemento)

            # Aplicar formatos
            self.aplicar_formato_estandar(nuevo_doc)
            self.aplicar_formato_avanzado(nuevo_doc)

            # Guardar el documento (sobrescribir el original)
            nombre_base = os.path.splitext(os.path.basename(archivo_docx))[0]
            extension = os.path.splitext(archivo_docx)[1]
            name = f"{nombre_base}{extension}"
            nuevo_docx = os.path.join(self.output_carpeta, name)
            nuevo_doc.save(nuevo_docx)

            return True, ""

        except Exception as e:
            return False, str(e)

    def procesar_documentos(self):
        """Función principal que orquesta todo el proceso"""
        if not DOCX_AVAILABLE:
            QMessageBox.critical(self, "Error",
                                 "La biblioteca python-docx no está disponible.\n\n"
                                 "Instala con: pip install python-docx")
            return

        # Verificar paths
        if not os.path.exists(self.caratula_path):
            QMessageBox.warning(self, "Error", "El archivo de carátula no existe.")
            return

        if not os.path.exists(self.carpeta_path):
            QMessageBox.warning(self, "Error", "La carpeta de documentos no existe.")
            return

        self.log("\n=== INICIANDO PROCESAMIENTO ===")
        self.log(f"Carátula: {self.caratula_path}")
        self.log(f"Carpeta: {self.carpeta_path}")

        directorio_padre = os.path.dirname(self.carpeta_path)
        self.output_carpeta = os.path.join(directorio_padre, "03.Outputs")
        os.makedirs(self.output_carpeta, exist_ok=True)

        # Buscar archivos .docx
        self.log("Buscando archivos .docx...")
        archivos_docx = self.buscar_docx_recursivamente(self.carpeta_path)

        if not archivos_docx:
            self.log("No se encontraron archivos .docx en la carpeta seleccionada.")
            QMessageBox.information(self, "Información",
                                    "No se encontraron archivos .docx en la carpeta seleccionada.")
            return

        self.log(f"Se encontraron {len(archivos_docx)} archivos .docx")

        # Crear diálogo de progreso
        progress = QProgressDialog("Procesando documentos...", "Cancelar", 0, len(archivos_docx), self)
        progress.setWindowTitle("Procesando")
        progress.setWindowModality(QtCore.Qt.WindowModal)
        progress.show()

        # Procesar cada archivo
        exitosos = 0
        fallidos = 0
        errores_detallados = []

        for i, archivo_docx in enumerate(archivos_docx):
            if progress.wasCanceled():
                self.log("Proceso cancelado por el usuario.")
                break

            progress.setValue(i)
            progress.setLabelText(f"Procesando {i + 1}/{len(archivos_docx)}: {os.path.basename(archivo_docx)}")
            QApplication.processEvents()

            self.log(f"Procesando: {os.path.basename(archivo_docx)}")

            success, error_msg = self.insertar_caratula_y_formatear(archivo_docx, self.caratula_path)

            if success:
                self.log(f"   ✓ Completado")
                exitosos += 1
            else:
                self.log(f"   ✗ Error: {error_msg}")
                fallidos += 1
                errores_detallados.append(f"{os.path.basename(archivo_docx)}: {error_msg}")

        progress.setValue(len(archivos_docx))

        # Mostrar resumen
        self.log("\n=== RESUMEN ===")
        self.log(f"Documentos procesados exitosamente: {exitosos}")
        self.log(f"Documentos con errores: {fallidos}")
        self.log(f"Total procesados: {exitosos + fallidos}")

        # Mostrar mensaje final
        mensaje = (f"Procesamiento completado:\n"
                   f"✓ Exitosos: {exitosos}\n"
                   f"✗ Fallidos: {fallidos}\n"
                   f"Total: {len(archivos_docx)}")

        if fallidos > 0:
            mensaje += f"\n\nErrores encontrados:\n" + "\n".join(
                errores_detallados[:5])  # Mostrar solo primeros 5 errores
            if len(errores_detallados) > 5:
                mensaje += f"\n... y {len(errores_detallados) - 5} más"

        QMessageBox.information(self, "Proceso Completado", mensaje)


# Función para ejecutar desde FreeCAD
def run_document_processor():
    """Función principal para ejecutar el procesador desde FreeCAD"""
    # Verificar si python-docx está disponible
    if not DOCX_AVAILABLE:
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Critical)
        msg.setText("Biblioteca python-docx no encontrada")
        msg.setInformativeText(
            "Para usar este script necesitas instalar python-docx:\n\n"
            "1. Abre la consola de FreeCAD\n"
            "2. Ejecuta: import subprocess, sys\n"
            "3. Ejecuta: subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'python-docx'])\n\n"
            "O instala desde una terminal externa con: pip install python-docx"
        )
        msg.setWindowTitle("Dependencia faltante")
        msg.exec_()
        return

    # Crear y mostrar la interfaz
    dialog = DocumentProcessor(FreeCADGui.getMainWindow())
    dialog.exec_()

class generateDocuments:
    def GetResources(self):
        return {'Pixmap': str(os.path.join(DirIcons, "house.svg")),
                'MenuText': "DocumentGenerator",
                'Accel': "D, G",
                'ToolTip': "Creates a Building object from setup dialog."}

    def IsActive(self):
        return not FreeCAD.ActiveDocument is None


    def Activated(self):
        run_document_processor()