import streamlit as st
import time
import urllib.request
import urllib.error
import os
import re
import io
from html.parser import HTMLParser
from urllib.parse import quote

import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment

from reportlab.lib.pagesizes import letter
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors


# --- CONFIGURACIÓN ---
BASE_URL = "https://iglam.cl/all"
MAX_PAGINAS = 15
TIMEOUT = 10
INTENTOS = 3
NUMERO_WHATSAPP = "56988438256"


# --- TÍTULO DE LA APP ---
st.set_page_config(page_title="Generador de Catálogo", page_icon="🛍️", layout="wide")
st.title("🛍️ Generador de Catálogo de Perfumería")
st.write("Haz clic en el botón para extraer los productos y generar el Excel y el PDF del catálogo. Todo el proceso se ejecuta en el servidor de Streamlit.")


# --- CLASE PARSER ---
class ProductoListParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.productos = []
        self.producto = None
        self.captura = None
        self.texto = []

    def handle_starttag(self, tag, attrs):
        atributos = dict(attrs)
        clases = atributos.get("class", "").split()

        if tag == "article" and "product-block" in clases:
            self.producto = {"Producto": "Sin titulo", "Marca": "N/A", "Precio": "", "Imagen": ""}
        elif self.producto and tag == "a" and "product-block__name" in clases:
            self.captura = (tag, "Producto")
            self.texto = []
        elif self.producto and tag == "span" and "product-block__brand" in clases:
            self.captura = (tag, "Marca")
            self.texto = []
        elif self.producto and tag == "div" and "product-block__price" in clases:
            self.captura = (tag, "Precio")
            self.texto = []
        elif self.producto and tag == "img":
            img_url = atributos.get("src") or atributos.get("data-src") or ""
            if img_url:
                if img_url.startswith("//"):
                    img_url = "https:" + img_url
                if "icon" not in img_url and not self.producto["Imagen"]:
                    self.producto["Imagen"] = img_url

    def handle_data(self, data):
        if self.captura:
            self.texto.append(data)

    def handle_endtag(self, tag):
        if self.captura and self.captura[0] == tag:
            texto_capturado = " ".join("".join(self.texto).split())
            if self.captura[1] == "Precio":
                self.producto["Precio"] += " " + texto_capturado
            else:
                self.producto[self.captura[1]] = texto_capturado
            if self.captura[1] != "Precio" or tag == "div":
                self.captura = None
                self.texto = []
        elif tag == "article" and self.producto:
            if not self.producto.get("Precio"):
                self.producto["Precio"] = "0"
            self.productos.append(self.producto)
            self.producto = None


# --- FUNCIONES AUXILIARES ---
def analizar_genero_y_notas(titulo_prod, marca_prod):
    texto_total = f"{titulo_prod} {marca_prod}".lower()

    if any(t in texto_total for t in ["homme", "man", "men", "caballero", "for men", "pour homme", "invictus", "sauvage", "le male"]):
        genero = "Hombre"
    elif any(t in texto_total for t in ["femme", "woman", "women", "dama", "for women", "pour femme", "good girl", "la vie est belle"]):
        genero = "Mujer"
    elif "unisex" in texto_total or "genderless" in texto_total:
        genero = "Unisex"
    else:
        genero = "Unisex / Versatil"

    if any(t in texto_total for t in ["intense", "parfum", "elixir", "oud"]):
        notas = "Amaderada / Especiada / Intensa"
    elif any(t in texto_total for t in ["sport", "fresh", "aqua", "water", "blue"]):
        notas = "Citrica / Acuatica / Fresca"
    elif any(t in texto_total for t in ["floral", "rose", "blossom", "flor"]):
        notas = "Floral / Dulce / Luminosa"
    elif any(t in texto_total for t in ["sweet", "vanilla", "honey", "caramel"]):
        notas = "Oriental / Dulce / Avainillada"
    else:
        notas = "Aromatica / Acorde equilibrado"

    return genero, notas


def obtener_productos(url):
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
    req = urllib.request.Request(url, headers=headers)
    for intento in range(1, INTENTOS + 1):
        try:
            with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
                html = response.read().decode("utf-8", errors="replace")
            parser = ProductoListParser()
            parser.feed(html)
            return parser.productos
        except (urllib.error.URLError, TimeoutError) as err:
            if intento == INTENTOS:
                raise err
            time.sleep(1)
    return []


# --- GENERADOR DE EXCEL ---
def generar_excel(todos_los_productos):
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Precios"
    ws.views.sheetView[0].showGridLines = True

    cabeceras = ["Nombre del Producto", "Precio Costo", "Genero", "Notas de Aroma", "Categoria", "Oferta"]
    ws.append(cabeceras)

    header_fill = PatternFill(start_color="004578", end_color="004578", fill_type="solid")
    header_font = Font(color="FFFFFF", bold=True)
    for col_num in range(1, len(cabeceras) + 1):
        cell = ws.cell(row=1, column=col_num)
        cell.fill = header_fill
        cell.font = header_font

    for i, item in enumerate(todos_los_productos, start=2):
        ws.append([
            item["Producto"],
            item["Precio Costo"],
            item["Genero"],
            item["Notas Aroma"],
            item["Categoria"],
            item["En Oferta"],
        ])
        ws.cell(row=i, column=6).alignment = Alignment(horizontal="center")

    buffer = io.BytesIO()
    wb.save(buffer)
    buffer.seek(0)
    return buffer


# --- GENERADOR DE PDF ---
def generar_pdf(todos_los_productos):
    buffer = io.BytesIO()

    class FondoDegradadoYMarco:
        def __call__(self, canvas_obj, doc_obj):
            if doc_obj.page == 1:
                return
            canvas_obj.saveState()
            ancho, alto = letter
            pasos = 50
            c_ini = colors.HexColor('#F7F3EE')
            c_fin = colors.HexColor('#EFEAE2')
            for i in range(pasos):
                y = (alto / pasos) * i
                h = alto / pasos + 1
                r = c_ini.red + (c_fin.red - c_ini.red) * (i / pasos)
                g = c_ini.green + (c_fin.green - c_ini.green) * (i / pasos)
                b = c_ini.blue + (c_fin.blue - c_ini.blue) * (i / pasos)
                canvas_obj.setFillColor(colors.Color(r, g, b))
                canvas_obj.rect(0, y, ancho, h, fill=1, stroke=0)
            canvas_obj.setStrokeColor(colors.HexColor('#D4AF37'))
            canvas_obj.setLineWidth(1.5)
            canvas_obj.rect(20, 20, ancho - 40, alto - 40)
            canvas_obj.setStrokeColor(colors.HexColor('#C5A059'))
            canvas_obj.setLineWidth(0.5)
            canvas_obj.rect(24, 24, ancho - 48, alto - 48)
            canvas_obj.setFont("Helvetica", 8)
            canvas_obj.setFillColor(colors.HexColor('#8C7B75'))
            canvas_obj.drawRightString(ancho - 35, 32, f"Pagina {canvas_obj._pageNumber}")
            canvas_obj.drawString(35, 32, "Coleccion Exclusiva de Perfumeria Fina")
            canvas_obj.restoreState()

    doc = SimpleDocTemplate(
        buffer, pagesize=letter,
        rightMargin=35, leftMargin=35, topMargin=40, bottomMargin=45
    )

    styles = getSampleStyleSheet()
    estilo_titulo = ParagraphStyle('T', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=22, leading=26, textColor=colors.HexColor('#FFFFFF'), alignment=1, spaceAfter=4)
    estilo_sub = ParagraphStyle('S', parent=styles['Normal'], fontName='Helvetica', fontSize=9.5, leading=13, textColor=colors.HexColor('#D4AF37'), alignment=1)
    estilo_prod_nombre = ParagraphStyle('PN', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=9.5, leading=13, textColor=colors.HexColor('#2C221E'), alignment=1)
    estilo_prod_info = ParagraphStyle('PI', parent=styles['Normal'], fontName='Helvetica', fontSize=7, leading=9, textColor=colors.HexColor('#8C7B75'), alignment=1)
    estilo_prod_precio = ParagraphStyle('PP', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=10, leading=13, textColor=colors.HexColor('#7A4E1B'), alignment=1)
    estilo_oferta = ParagraphStyle('O', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=8.5, leading=11, textColor=colors.HexColor('#D9534F'), alignment=1)
    estilo_boton = ParagraphStyle('B', parent=styles['Normal'], fontName='Helvetica-Bold', fontSize=8, leading=10, textColor=colors.HexColor('#25D366'), alignment=1)
    estilo_portada_titulo = ParagraphStyle('PT', fontName='Helvetica-Bold', fontSize=24, leading=30, textColor=colors.HexColor('#D4AF37'), alignment=1)
    estilo_portada_sub = ParagraphStyle('PS', fontName='Helvetica', fontSize=12, leading=16, textColor=colors.HexColor('#F7F3EE'), alignment=1)
    estilo_bienvenida_body = ParagraphStyle('BB', fontName='Helvetica', fontSize=9.5, leading=14, textColor=colors.HexColor('#2C221E'), alignment=0)
    estilo_bienvenida_dest = ParagraphStyle('BD', fontName='Helvetica-Oblique', fontSize=10, leading=14, textColor=colors.HexColor('#7A4E1B'), alignment=1)

    elementos = []

    def dibujar_portada(canvas_obj, doc_obj):
        canvas_obj.saveState()
        ancho, alto = letter
        canvas_obj.setFillColor(colors.HexColor('#2C221E'))
        canvas_obj.rect(0, 0, ancho, alto, fill=1, stroke=0)
        canvas_obj.setStrokeColor(colors.HexColor('#D4AF37'))
        canvas_obj.setLineWidth(2)
        canvas_obj.rect(30, 30, ancho - 60, alto - 60)
        canvas_obj.setLineWidth(0.5)
        canvas_obj.rect(36, 36, ancho - 72, alto - 72)
        canvas_obj.restoreState()

    # Portada
    portada = [
        Spacer(1, 140),
        Paragraph("COLECCION EXCLUSIVA", estilo_portada_sub),
        Spacer(1, 15),
        Paragraph("CATALOGO DE PERFUMERIA FINA", estilo_portada_titulo),
        Spacer(1, 10),
        Paragraph("Esencias a medida - Maxima Duracion y Elegancia", estilo_sub),
        Spacer(1, 180),
        Paragraph("Edicion 2026", estilo_portada_titulo),
    ]
    tabla_portada = Table([[portada]], colWidths=[540])
    tabla_portada.setStyle(TableStyle([('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE')]))
    elementos.append(tabla_portada)
    elementos.append(PageBreak())

    # Bienvenida
    elementos.append(Spacer(1, 15))
    bienvenida = [
        [Paragraph("<b>DESCUBRE TU PROXIMA FRAGANCIA FAVORITA!</b>", estilo_portada_titulo)],
        [Spacer(1, 8)],
        [Paragraph("Un gran perfume no es solo un aroma: es tu marca personal, esa estela inolvidable que dejas al pasar.", estilo_bienvenida_dest)],
        [Spacer(1, 10)],
        [Paragraph("En este catalogo se ha reunido una seleccion inspirada en las fragancias de alta gama mas iconicas.", estilo_bienvenida_body)],
        [Spacer(1, 8)],
        [Paragraph("<b>Como hacer tu pedido?</b> Presiona el boton verde <b>[ Pedir por WhatsApp ]</b>.", estilo_bienvenida_body)],
    ]
    tb = Table(bienvenida, colWidths=[500])
    tb.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#F7F3EE')),
        ('BOX', (0, 0), (-1, -1), 1, colors.HexColor('#D4AF37')),
        ('PADDING', (0, 0), (-1, -1), 12),
    ]))
    elementos.append(tb)
    elementos.append(Spacer(1, 20))

    # Header catálogo
    header_data = [
        [Paragraph("CATALOGO DE PERFUMERIA", estilo_titulo)],
        [Paragraph("ESENCIAS A PEDIDO - ALTA CALIDAD Y DURACION", estilo_sub)]
    ]
    header_table = Table(header_data, colWidths=[540])
    header_table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#2C221E')),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 14),
        ('TOPPADDING', (0, 0), (-1, -1), 16),
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('BOTTOMBORDER', (0, 1), (-1, 1), 3, colors.HexColor('#D4AF37')),
    ]))
    elementos.append(header_table)
    elementos.append(Spacer(1, 15))

    # Grilla de productos
    filas_tabla = []
    fila_actual = []

    for prod in todos_los_productos:
        precio_fmt = f"${int(prod['Precio Costo']):,}".replace(",", ".")

        img_celda = Paragraph("<i>Sin Imagen</i>", estilo_prod_info)

        mensaje_texto = (
            f"Hola Julio, estuve revisando el catalogo y me interesa comprar el producto: \n"
            f"- {prod['Producto']}\n"
            f"Precio: {precio_fmt} CLP.\n"
            f"Me confirmas disponibilidad y los datos para realizar la transferencia?"
        )
        mensaje_encoded = quote(mensaje_texto)
        url_whatsapp = f"https://wa.me/{NUMERO_WHATSAPP}?text={mensaje_encoded}"

        contenido = [
            Spacer(1, 3),
            img_celda,
            Spacer(1, 4),
            Paragraph(prod["Producto"], estilo_prod_nombre),
            Spacer(1, 1),
            Paragraph(f"<b>Cat:</b> {prod['Categoria']} | <b>Genero:</b> {prod['Genero']}", estilo_prod_info),
            Spacer(1, 1),
            Paragraph(f"<b>Notas:</b> {prod['Notas Aroma']}", estilo_prod_info),
        ]

        if prod["En Oferta"].upper() in ("SI", "SÍ"):
            contenido.extend([Spacer(1, 2), Paragraph("OFERTA!", estilo_oferta)])

        contenido.extend([
            Spacer(1, 3),
            Paragraph(f"{precio_fmt} CLP", estilo_prod_precio),
            Spacer(1, 4),
            Paragraph(f'<a href="{url_whatsapp}"><b>[ Pedir por WhatsApp ]</b></a>', estilo_boton),
            Spacer(1, 3),
        ])

        card = Table([[contenido]], colWidths=[172])
        card.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#FFFFFF')),
            ('BOX', (0, 0), (-1, -1), 1, colors.HexColor('#E2D7CC')),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('TOPPADDING', (0, 0), (-1, -1), 4),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ]))
        fila_actual.append(card)

        if len(fila_actual) == 3:
            filas_tabla.append(fila_actual)
            fila_actual = []

    if fila_actual:
        while len(fila_actual) < 3:
            fila_actual.append(Paragraph("", styles['Normal']))
        filas_tabla.append(fila_actual)

    if filas_tabla:
        grilla = Table(filas_tabla, colWidths=[180, 180, 180])
        grilla.setStyle(TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
            ('TOPPADDING', (0, 0), (-1, -1), 6),
        ]))
        elementos.append(grilla)

    doc.build(elementos, onFirstPage=dibujar_portada, onLaterPages=FondoDegradadoYMarco())
    buffer.seek(0)
    return buffer


# --- FUNCIÓN PRINCIPAL DE LA APP ---
def main():
    if st.button("🚀 Generar Catálogo", type="primary"):
        progreso = st.progress(0)
        estado = st.empty()

        estado.info("Iniciando extracción de productos...")
        todos_los_productos = []
        pagina = 1

        while pagina <= MAX_PAGINAS:
            url = f"{BASE_URL}?page={pagina}"
            estado.write(f"📄 Descargando página {pagina} de {MAX_PAGINAS}...")
            try:
                productos = obtener_productos(url)
                if not productos:
                    estado.info("No se encontraron más productos. Finalizando extracción.")
                    break

                for producto in productos:
                    titulo = producto.get("Producto", "Sin titulo")
                    marca = producto.get("Marca", "N/A")
                    genero_detectado, notas_detectadas = analizar_genero_y_notas(titulo, marca)

                    precio_raw = producto.get("Precio", "0")
                    precios_encontrados = re.findall(r'[\d\.]+', precio_raw.replace("$", ""))
                    valores_numericos = []
                    for p_str in precios_encontrados:
                        p_limpio = p_str.replace(".", "").strip()
                        try:
                            val = float(p_limpio)
                            if val > 100:
                                valores_numericos.append(val)
                        except Exception:
                            pass

                    if valores_numericos:
                        precio_costo = min(valores_numericos)
                        tiene_oferta = len(set(valores_numericos)) > 1 or (max(valores_numericos) > precio_costo)
                    else:
                        precio_costo = 0.0
                        tiene_oferta = False

                    todos_los_productos.append({
                        "Producto": titulo,
                        "Precio Costo": precio_costo,
                        "Categoria": marca,
                        "Genero": genero_detectado,
                        "Notas Aroma": notas_detectadas,
                        "En Oferta": "SI" if tiene_oferta else "NO",
                    })

                pagina += 1
                progreso.progress(min(pagina / MAX_PAGINAS, 0.9))
            except Exception as err:
                st.error(f"Error en página {pagina}: {err}")
                break

        if not todos_los_productos:
            st.warning("No se pudieron extraer productos. Intenta nuevamente.")
            return

        estado.success(f"✅ Extracción completa: {len(todos_los_productos)} productos procesados.")

        # Generar Excel
        estado.write("📊 Generando archivo Excel...")
        excel_buffer = generar_excel(todos_los_productos)

        # Generar PDF
        estado.write("📄 Generando catálogo PDF...")
        pdf_buffer = generar_pdf(todos_los_productos)

        progreso.progress(1.0)
        estado.success("🎉 ¡Proceso completado! Descarga tus archivos abajo.")

        # Botones de descarga
        st.subheader("📥 Descarga tus archivos")
        col1, col2 = st.columns(2)
        with col1:
            st.download_button(
                label="⬇️ Descargar Excel",
                data=excel_buffer,
                file_name="precios_para_editar.xlsx",
                mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                use_container_width=True,
            )
        with col2:
            st.download_button(
                label="⬇️ Descargar PDF",
                data=pdf_buffer,
                file_name="catalogo_perfumeria.pdf",
                mime="application/pdf",
                use_container_width=True,
            )


if __name__ == "__main__":
    main()
