#!/usr/bin/env python3
"""
Interfaz gráfica para Boletín Oficial → CSV
Usa el motor de boletin_to_csv.py sin modificarlo.
Ambos archivos deben estar en la misma carpeta.
"""

import sys
import os
import re
import csv
import threading
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from pathlib import Path
from collections import Counter

# ── Configuración persistente ────────────────────────────────────────────────
CONFIG_FILE = Path(__file__).parent / ".boletin_gui_config.txt"

def cargar_config():
    """Devuelve (titulo, carpeta) guardados, o ('', '') si no hay nada."""
    try:
        if CONFIG_FILE.exists():
            lineas = CONFIG_FILE.read_text(encoding="utf-8").splitlines()
            titulo  = lineas[0].strip() if len(lineas) > 0 else ""
            carpeta = lineas[1].strip() if len(lineas) > 1 else ""
            return titulo, carpeta
    except Exception:
        pass
    return "", ""

def guardar_config(titulo, carpeta):
    try:
        CONFIG_FILE.write_text(f"{titulo}\n{carpeta}", encoding="utf-8")
    except Exception:
        pass


# ── Aplicación principal ─────────────────────────────────────────────────────
class BoletinApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Boletín Oficial → CSV")
        self.resizable(True, True)
        self._avisos_analizados = None
        self._center_window(560, 660)
        self._setup_styles()
        self._build_ui()

    def _center_window(self, w, h):
        self.update_idletasks()
        sw = self.winfo_screenwidth()
        sh = self.winfo_screenheight()
        x = (sw - w) // 2
        y = (sh - h) // 2
        self.geometry(f"{w}x{h}+{x}+{y}")

    def _setup_styles(self):
        self.configure(bg="#F5F5F0")
        style = ttk.Style(self)
        style.theme_use("clam")

        BG       = "#F5F5F0"
        PANEL    = "#EEEEE8"
        ACCENT   = "#1A3A5C"
        ENTRY_BG = "#FFFFFF"
        BORDER   = "#CCCCBF"

        style.configure("TFrame",         background=BG)
        style.configure("Panel.TFrame",   background=PANEL, relief="flat", borderwidth=1)
        style.configure("TLabel",         background=BG, font=("Georgia", 10), foreground="#333333")
        style.configure("Header.TLabel",  background=BG, font=("Georgia", 15, "bold"), foreground=ACCENT)
        style.configure("Sub.TLabel",     background=BG, font=("Georgia", 9), foreground="#666655")
        style.configure("Panel.TLabel",   background=PANEL, font=("Georgia", 10), foreground="#333333")
        style.configure("TEntry",         fieldbackground=ENTRY_BG, font=("Consolas", 10), relief="flat", borderwidth=1)
        style.configure("TSpinbox",       fieldbackground=ENTRY_BG, font=("Consolas", 10))
        style.configure("TCheckbutton",   background=BG, font=("Georgia", 10), foreground="#333333")
        style.configure("Secondary.TButton",
                        background=PANEL, foreground=ACCENT,
                        font=("Georgia", 10), padding=(10, 6), relief="flat", borderwidth=1)
        style.map("Secondary.TButton", background=[("active", "#DDDDCC")])

        self.ACCENT = ACCENT
        self.BG     = BG
        self.PANEL  = PANEL
        self.BORDER = BORDER

    def _build_ui(self):
        titulo_ant, carpeta_ant = cargar_config()
        PAD  = 20
        root = ttk.Frame(self, padding=PAD)
        root.pack(fill="both", expand=True)

        # ── Encabezado ──────────────────────────────────────────────────────
        ttk.Label(root, text="Boletín Oficial → CSV", style="Header.TLabel").pack(anchor="w")
        ttk.Label(root, text="Generador de entradas para WordPress", style="Sub.TLabel").pack(anchor="w", pady=(0, 12))
        tk.Frame(root, height=1, bg=self.BORDER).pack(fill="x", pady=(0, 14))

        # ── 1 · Título ───────────────────────────────────────────────────────
        self._section(root, "1 · Título del boletín")
        self.titulo_var = tk.StringVar(value=titulo_ant)
        self.entry_titulo = ttk.Entry(root, textvariable=self.titulo_var, width=58)
        self.entry_titulo.pack(fill="x", ipady=5, pady=(0, 14))
        self.after(100, lambda: (self.entry_titulo.focus_set(),
                                  self.entry_titulo.selection_range(0, "end")))

        # ── 2 · Archivo Word ─────────────────────────────────────────────────
        self._section(root, "2 · Archivo Word")
        file_row = ttk.Frame(root)
        file_row.pack(fill="x", pady=(4, 4))

        self.archivo_var = tk.StringVar()
        ttk.Entry(file_row, textvariable=self.archivo_var, width=42).pack(side="left", ipady=4)
        ttk.Button(file_row, text="Buscar…", style="Secondary.TButton",
                   command=self._buscar_archivo).pack(side="left", padx=(8, 0))

        # Panel de análisis previo (oculto hasta que se elija archivo)
        self.analisis_frame = ttk.Frame(root, style="Panel.TFrame", padding=10)
        self.analisis_text  = tk.StringVar(value="")
        self.analisis_lbl   = ttk.Label(self.analisis_frame, textvariable=self.analisis_text,
                                        style="Panel.TLabel", justify="left")
        self.analisis_lbl.pack(anchor="w")

        tk.Frame(root, height=1, bg=self.BORDER).pack(fill="x", pady=(12, 10))

        # ── 3 · Opciones ─────────────────────────────────────────────────────
        self._section(root, "3 · Opciones de exportación")
        panel = ttk.Frame(root, style="Panel.TFrame", padding=12)
        panel.pack(fill="x", pady=(4, 14))

        self.dividir_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(panel, text="Dividir en varios archivos CSV",
                        variable=self.dividir_var, command=self._toggle_lote,
                        style="TCheckbutton").pack(anchor="w")

        lote_row = ttk.Frame(panel)
        lote_row.pack(anchor="w", pady=(6, 0))
        ttk.Label(lote_row, text="Entradas por archivo:", style="Panel.TLabel").pack(side="left")
        self.lote_var  = tk.IntVar(value=25)
        self.spin_lote = ttk.Spinbox(lote_row, from_=5, to=500,
                                     textvariable=self.lote_var, width=6, state="normal")
        self.spin_lote.pack(side="left", padx=(8, 0))

        # ── 4 · Carpeta destino ───────────────────────────────────────────────
        self._section(root, "4 · Carpeta de destino")
        dest_row = ttk.Frame(root)
        dest_row.pack(fill="x", pady=(4, 14))

        destino_inicial = carpeta_ant if carpeta_ant and Path(carpeta_ant).exists() else str(Path.home())
        self.destino_var = tk.StringVar(value=destino_inicial)
        ttk.Entry(dest_row, textvariable=self.destino_var, width=42).pack(side="left", ipady=4)
        ttk.Button(dest_row, text="Cambiar…", style="Secondary.TButton",
                   command=self._buscar_destino).pack(side="left", padx=(8, 0))

        # ── Botón Procesar ────────────────────────────────────────────────────
        tk.Frame(root, height=1, bg=self.BORDER).pack(fill="x", pady=(8, 14))

        self.btn_procesar = tk.Button(
            root, text="  Procesar  ", command=self._procesar,
            bg="#1A3A5C", fg="#FFFFFF", font=("Georgia", 12, "bold"),
            relief="groove", cursor="hand2", padx=30, pady=8,
            activebackground="#254E7A", activeforeground="#FFFFFF",
        )
        self.btn_procesar.pack(pady=(0, 10))

        # ── Log ───────────────────────────────────────────────────────────────
        self.log_var = tk.StringVar(value="")
        self.log_lbl = ttk.Label(root, textvariable=self.log_var,
                                 style="Sub.TLabel", wraplength=500, justify="left")
        self.log_lbl.pack(anchor="w", pady=(6, 0))

    # ── helpers UI ─────────────────────────────────────────────────────────────
    def _section(self, parent, text):
        ttk.Label(parent, text=text,
                  font=("Georgia", 10, "bold"),
                  background=self.BG,
                  foreground=self.ACCENT).pack(anchor="w", pady=(0, 2))

    def _toggle_lote(self):
        self.spin_lote.configure(state="normal" if self.dividir_var.get() else "disabled")

    def _buscar_archivo(self):
        path = filedialog.askopenfilename(
            title="Seleccionar Boletín",
            filetypes=[("Documentos Word", "*.doc *.docx"), ("Todos los archivos", "*.*")]
        )
        if not path:
            return
        self.archivo_var.set(path)
        # Mostrar panel y lanzar análisis
        self._avisos_analizados = None
        self.analisis_text.set("🔍 Analizando documento…")
        self.analisis_lbl.configure(foreground="#444433")
        self.analisis_frame.pack(fill="x", pady=(6, 0))
        self.btn_procesar.configure(state="disabled")
        threading.Thread(target=self._analizar, args=(path,), daemon=True).start()

    def _buscar_destino(self):
        path = filedialog.askdirectory(title="Carpeta de destino")
        if path:
            self.destino_var.set(path)

    # ── Análisis previo ────────────────────────────────────────────────────────
    def _analizar(self, archivo):
        try:
            script_dir = Path(__file__).parent
            if str(script_dir) not in sys.path:
                sys.path.insert(0, str(script_dir))
            import boletin_to_csv as engine

            arch = archivo
            if arch.lower().endswith(".doc"):
                self.after(0, lambda: self.analisis_text.set("🔄 Convirtiendo .doc → .docx…"))
                arch = engine.convertir_doc_a_docx(arch)

            titulo     = self.titulo_var.get().strip()
            match_num  = re.search(r'N[ºo°]?\s*(\d+)', titulo, re.IGNORECASE)
            numero     = match_num.group(1) if match_num else ""
            if numero and re.search(r'E\.?C\.?', titulo, re.IGNORECASE):
                numero += "EC"
            match_anio = re.search(r'\b(20\d{2})\b', titulo)
            anio       = match_anio.group(1) if match_anio else ""
            bloque_pdf = engine.armar_bloque_pdf(numero, anio) if (numero and anio) else ""

            avisos = engine.extraer_avisos(arch, titulo, anio, numero, bloque_pdf)
            self._avisos_analizados = avisos
            self.after(0, lambda: self._mostrar_analisis(avisos))

        except Exception as e:
            err = str(e)
            self.after(0, lambda: self._error_analisis(err))

    def _mostrar_analisis(self, avisos):
        if not avisos:
            self.analisis_text.set("⚠ No se encontraron avisos en el documento.")
            self.analisis_lbl.configure(foreground="#CC6600")
            return

        # Mostrar línea breve en el panel
        self.analisis_text.set(f"✓ {len(avisos)} avisos encontrados — ver detalle en la ventana")
        self.analisis_lbl.configure(foreground="#1A4A1A")
        self.btn_procesar.configure(state="normal")

        # Ventana emergente con el resumen completo
        # Resumen en orden de aparición en el documento
        categorias_vistas = []
        resumen = {}
        for a in avisos:
            cat = a["tax_category"]
            if cat not in resumen:
                categorias_vistas.append(cat)
                resumen[cat] = 0
            resumen[cat] += 1
        detalle = "\n".join(f"  {resumen[cat]:3d}   {cat}" for cat in categorias_vistas)
        messagebox.showinfo(
            "Análisis del documento",
            f"{len(avisos)} avisos encontrados.\n\nResumen por categoría:\n\n{detalle}"
        )

    def _error_analisis(self, msg):
        self.analisis_text.set(f"✗ Error al analizar: {msg}")
        self.analisis_lbl.configure(foreground="#AA2222")
        self.btn_procesar.configure(state="normal")

    # ── Procesamiento final ────────────────────────────────────────────────────
    def _log(self, msg, color=None):
        self.log_var.set(msg)
        self.log_lbl.configure(foreground=color or "#555544")
        self.update_idletasks()

    def _procesar(self):
        archivo = self.archivo_var.get().strip()
        titulo  = self.titulo_var.get().strip()
        destino = self.destino_var.get().strip()

        if not archivo:
            messagebox.showwarning("Falta archivo", "Seleccioná el archivo Word del boletín.")
            return
        if not Path(archivo).exists():
            messagebox.showerror("Archivo no encontrado", f"No se encontró:\n{archivo}")
            return
        if not titulo:
            messagebox.showwarning("Falta título", "Ingresá el título del boletín.")
            return
        if not destino or not Path(destino).exists():
            messagebox.showwarning("Carpeta inválida", "Elegí una carpeta de destino válida.")
            return

        guardar_config(titulo, destino)
        self.btn_procesar.configure(state="disabled")
        self._log("⏳ Generando archivos CSV…")

        threading.Thread(target=self._run_engine,
                         args=(archivo, titulo, destino),
                         daemon=True).start()

    def _run_engine(self, archivo, titulo, destino):
        try:
            script_dir = Path(__file__).parent
            if str(script_dir) not in sys.path:
                sys.path.insert(0, str(script_dir))
            import boletin_to_csv as engine

            # Usar avisos ya analizados si están disponibles
            if self._avisos_analizados is not None:
                avisos = self._avisos_analizados
            else:
                arch = archivo
                if arch.lower().endswith(".doc"):
                    self._log("🔄 Convirtiendo .doc → .docx…")
                    arch = engine.convertir_doc_a_docx(arch)
                match_num  = re.search(r'N[ºo°]?\s*(\d+)', titulo, re.IGNORECASE)
                numero     = match_num.group(1) if match_num else ""
                if numero and re.search(r'E\.?C\.?', titulo, re.IGNORECASE):
                    numero += "EC"
                match_anio = re.search(r'\b(20\d{2})\b', titulo)
                anio       = match_anio.group(1) if match_anio else ""
                bloque_pdf = engine.armar_bloque_pdf(numero, anio) if (numero and anio) else ""
                avisos     = engine.extraer_avisos(arch, titulo, anio, numero, bloque_pdf)

            if not avisos:
                self._log("⚠ No se encontraron avisos.", "#CC6600")
                self.after(0, lambda: self.btn_procesar.configure(state="normal"))
                return

            campos = ["post_title", "post_content", "post_status",
                      "post_type", "tax_category", "tax_post_tag"]
            stem   = Path(archivo).stem

            if self.dividir_var.get():
                tam   = self.lote_var.get()
                lotes = [avisos[i:i+tam] for i in range(0, len(avisos), tam)]
                for idx, lote in enumerate(lotes, 1):
                    nombre = Path(destino) / f"{stem}_parte{idx}_avisos.csv"
                    with open(nombre, "w", newline="", encoding="utf-8-sig") as f:
                        writer = csv.DictWriter(f, fieldnames=campos)
                        writer.writeheader()
                        writer.writerows(lote)
                msg = f"✓ {len(avisos)} avisos → {len(lotes)} archivos CSV\nGuardados en: {destino}"
            else:
                salida = Path(destino) / f"{stem}_avisos.csv"
                with open(salida, "w", newline="", encoding="utf-8-sig") as f:
                    writer = csv.DictWriter(f, fieldnames=campos)
                    writer.writeheader()
                    writer.writerows(avisos)
                msg = f"✓ {len(avisos)} avisos → {salida.name}\nGuardado en: {destino}"

            self.after(0, lambda: self._finalizar(msg))

        except Exception as e:
            err = str(e)
            self.after(0, lambda: self._error(err))

    def _finalizar(self, msg):
        self._log(msg, "#1A6B2A")
        self.btn_procesar.configure(state="normal")
        messagebox.showinfo("✓ Proceso completado", msg)

    def _error(self, msg):
        self._log(f"✗ Error: {msg}", "#AA2222")
        self.btn_procesar.configure(state="normal")
        messagebox.showerror("Error al procesar", msg)


# ── Entry point ──────────────────────────────────────────────────────────────
if __name__ == "__main__":
    app = BoletinApp()
    app.mainloop()
