import feedparser
import google.generativeai as genai
import facebook
import socket
import requests
import re
import os
import textwrap
from bs4 import BeautifulSoup
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont

# Asegúrate de tener tu archivo config.py en la misma carpeta con estas variables
from config import PAGE_ID, FACEBOOK_TOKEN, GEMINI_API_KEY, FEEDS_HUANUCO

socket.setdefaulttimeout(60)
genai.configure(api_key=GEMINI_API_KEY)

# 1. CARRUSEL DE MODELOS (Sistema Anticaídas por Cuota - Actualizado 2026)
MODELOS_DISPONIBLES = [
    'models/gemini-3.1-pro-preview',       
    'models/gemini-3-flash-preview',       
    'models/gemini-3.1-flash-lite-preview', 
    'models/gemini-3-pro-preview',         
    'models/gemini-2.5-pro',               
    'models/gemini-2.5-flash',             
    'models/gemini-2.0-flash',             
    'models/gemini-2.0-flash-lite',        
    'models/gemini-flash-latest',          
    'models/gemini-pro-latest',            
    'models/gemma-3-27b-it',               
    'models/gemma-3-12b-it'                
]

graph = facebook.GraphAPI(access_token=FACEBOOK_TOKEN)

# --- FUNCIONES DE MEMORIA ANTI-DUPLICADOS (BLINDADAS) ---
# Obligamos al bot a usar siempre la carpeta exacta donde está el código
RUTA_BASE = os.path.dirname(os.path.abspath(__file__))
ARCHIVO_MEMORIA = os.path.join(RUTA_BASE, "publicadas.txt")

def noticia_ya_publicada(link):
    link_limpio = link.strip()
    if not os.path.exists(ARCHIVO_MEMORIA):
        return False
    with open(ARCHIVO_MEMORIA, "r", encoding="utf-8") as f:
        # Limpiamos cada línea guardada para asegurar una comparación perfecta
        publicados = [linea.strip() for linea in f.read().splitlines()]
    return link_limpio in publicados

def guardar_noticia_publicada(link):
    link_limpio = link.strip()
    with open(ARCHIVO_MEMORIA, "a", encoding="utf-8") as f:
        f.write(link_limpio + "\n")

# --- IA Y GENERACIÓN DE TEXTO ---
def intentar_generar_con_respaldo(prompt):
    for nombre_modelo in MODELOS_DISPONIBLES:
        try:
            print(f"--> Intentando con el modelo: {nombre_modelo}...")
            model = genai.GenerativeModel(nombre_modelo)
            response = model.generate_content(prompt)
            return response.text
        except Exception as e:
            if "429" in str(e) or "exhausted" in str(e).lower() or "404" in str(e):
                print(f"⚠️ Fallo en {nombre_modelo} (Cuota/No Encontrado). Pasando al siguiente...")
                continue
            else:
                print(f"❌ Error en modelo {nombre_modelo}: {e}")
                continue
    return None

def elegir_noticia_viral(todas_las_noticias):
    print("--> Paso 3: Analizando viralidad y relevancia local...")
    lista_titulos = ""
    for i, noti in enumerate(todas_las_noticias):
        lista_titulos += f"[{i}] {noti['titulo']} (Fuente: {noti['fuente']})\n"
        
    prompt = f"""
    Eres el Director de Vanguardia Noticias en Huánuco. Tienes esta lista de noticias:
    {lista_titulos}
    Tu tarea: Elige la noticia con MAYOR impacto social, político o económico para Huánuco.
    RESPONDE ÚNICAMENTE CON EL NÚMERO (ID). No digas nada más. Ejemplo: 2
    """
    respuesta = intentar_generar_con_respaldo(prompt)
    try:
        indice = int(re.search(r'\d+', respuesta).group())
        return todas_las_noticias[indice]
    except Exception:
        return todas_las_noticias[0]

def generar_redaccion_profunda(titulo, contexto, fuente):
    print(f"--> Paso 4: Redactando crónica con hashtag e identificación verídica...")
    prompt = f"""
    Eres el Editor Jefe de Vanguardia Noticias. Redacta una publicación para Facebook sobre esta noticia.
    
    TÍTULO ORIGINAL: {titulo}
    CONTEXTO REAL: {contexto}
    
    REGLAS ESTRICTAS DE REDACCIÓN:
    1. INICIO: Comienza SIEMPRE con un hashtag relevante en mayúsculas que combine el tema y la ubicación (ejemplo: #ALERTAHUÁNUCO, #ECONOMÍAPERÚ, #EMPRENDEDORESHUÁNUCO).
    2. TITULAR: Inmediatamente después del hashtag, en la misma línea o la siguiente, pon un titular IMPACTANTE en mayúsculas con un emoji de alerta (🚨, ⚠️, 🔴).
    3. IDENTIFICACIÓN VERÍDICA: Si la noticia menciona a una persona específica, IDENTIFÍCALO claramente por su nombre y cargo en la redacción.
    4. CUERPO: Escribe 3 a 4 párrafos cortos, serios y analíticos. Sin saludos ni presentaciones. Ve directo al grano.
    5. TONO: Periodismo de investigación profesional, objetivo e incisivo.
    6. FINAL: Termina el post exactamente en una nueva línea con '📰 Fuente: {fuente}'. No uses links ni URLs.
    """
    return intentar_generar_con_respaldo(prompt)

# --- EXTRACCIÓN VISUAL AVANZADA ---
def extraer_imagen_desde_web(url_articulo):
    print("--> Usando Visión de Rayos X Avanzada para aislar la foto real...")
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
        }
        respuesta = requests.get(url_articulo, headers=headers, timeout=15)
        soup = BeautifulSoup(respuesta.text, 'html.parser')

        palabras_prohibidas = ['logo', 'icon', 'default', 'avatar', 'header', 'banner', 'blank', 'spinner']

        def es_imagen_valida(url_img):
            if not url_img: return False
            return not any(prohibida in url_img.lower() for prohibida in palabras_prohibidas)

        meta_og = soup.find('meta', property='og:image') or soup.find('meta', attrs={'name': 'og:image'}) or soup.find('meta', attrs={'name': 'twitter:image'})
        if meta_og and es_imagen_valida(meta_og.get('content')):
            return meta_og.get('content')

        img_destacada = soup.find('img', class_=lambda c: c and ('wp-post-image' in c or 'attachment-large' in c))
        if img_destacada and es_imagen_valida(img_destacada.get('src')):
            return img_destacada.get('src')

        imagenes_lazy = soup.find_all('img')
        for img in imagenes_lazy:
            for atributo in ['data-src', 'data-original', 'data-lazy-src', 'lazy-src']:
                if img.has_attr(atributo) and es_imagen_valida(img[atributo]):
                    return img[atributo]

        etiquetas_source = soup.find_all('source')
        for source in etiquetas_source:
            if source.has_attr('srcset'):
                url_limpia = source['srcset'].split(',')[0].split(' ')[0]
                if es_imagen_valida(url_limpia):
                    return url_limpia

        articulo = soup.find('article') or soup.find('div', class_=re.compile(r'content|post|article|nota', re.I))
        if articulo:
            imagenes_articulo = articulo.find_all('img')
            for img in imagenes_articulo:
                src = img.get('src')
                if es_imagen_valida(src):
                    return src

    except Exception as e:
        print(f"--> Falló la extracción visual: {e}")
    
    return None

def descargar_fuente_letra():
    if not os.path.exists("Impact.ttf"):
        try:
            print("--> Descargando fuente tipográfica Impact-style...")
            url_fuente = "https://github.com/googlefonts/roboto/raw/main/src/hinted/Roboto-Black.ttf"
            respuesta = requests.get(url_fuente)
            with open("Impact.ttf", "wb") as f:
                f.write(respuesta.content)
        except Exception:
            pass

# --- DISEÑO GRÁFICO MODERNO, DINÁMICO Y ADAPTATIVO ---
def editar_imagen_con_texto(url_foto, titular, texto_post):
    print("--> Paso 5: Diseñando imagen periodística dinámica con hashtag inteligente...")
    try:
        descargar_fuente_letra()
        
        ANCHO_CANVAS = 1080
        
        # 1. Descargar y preparar la foto principal
        if url_foto:
            print(f"--> Extrayendo foto original sin filtros...")
            headers = {'User-Agent': 'Mozilla/5.0'}
            respuesta = requests.get(url_foto, headers=headers, timeout=10)
            img_noti = Image.open(BytesIO(respuesta.content)).convert("RGBA")
            
            w_orig, h_orig = img_noti.size
            ratio = ANCHO_CANVAS / w_orig
            nueva_h = int(h_orig * ratio)
            img_noti = img_noti.resize((ANCHO_CANVAS, nueva_h), Image.Resampling.LANCZOS)
        else:
            nueva_h = 720
            img_noti = Image.new('RGBA', (ANCHO_CANVAS, nueva_h), (50, 50, 50, 255))
            
        # 2. Configurar Textos y Fuentes (Buscando el Hashtag Real)
        hashtag_match = re.search(r'#[^\s]+', texto_post)
        if hashtag_match:
            hashtag_texto = hashtag_match.group(0).upper()
        else:
            hashtag_texto = "#NOTICIAHUÁNUCO"
            
        # Quitamos cualquier hashtag que haya quedado en el titular generado para evitar redundancia en la imagen
        titular_limpio = re.sub(r'#[^\s]+', '', titular).strip()

        tamano_hashtag = 40
        tamano_titular = 65
        try:
            font_hashtag = ImageFont.truetype("Impact.ttf", tamano_hashtag)
            font_titular = ImageFont.truetype("Impact.ttf", tamano_titular)
        except:
            font_hashtag = ImageFont.load_default()
            font_titular = ImageFont.load_default()

        lineas = textwrap.wrap(titular_limpio.upper(), width=26)
        
        # 3. Calcular Altura Dinámica del Lienzo
        interlineado = 15
        padding_top = 50
        padding_bottom = 70
        espacio_entre_hash_y_titulo = 25
        
        alto_bloque_titular = len(lineas) * (tamano_titular + interlineado)
        alto_caja_texto = padding_top + tamano_hashtag + espacio_entre_hash_y_titulo + alto_bloque_titular + padding_bottom
        
        grosor_linea_acento = 8
        ALTO_CANVAS_FINAL = nueva_h + grosor_linea_acento + alto_caja_texto

        # 4. Construir el Lienzo Final con Colores Modernos
        COLOR_FONDO_TEXTO = (15, 23, 42, 255) # Azul noche elegante
        COLOR_ACENTO = (250, 204, 21, 255)    # Amarillo vibrante
        
        img_final = Image.new('RGBA', (ANCHO_CANVAS, ALTO_CANVAS_FINAL), COLOR_FONDO_TEXTO)
        draw = ImageDraw.Draw(img_final)
        
        # Pegar foto original y línea de acento
        img_final.paste(img_noti, (0, 0))
        draw.rectangle([0, nueva_h, ANCHO_CANVAS, nueva_h + grosor_linea_acento], fill=COLOR_ACENTO)
        
        # 5. Dibujar los Textos de forma jerárquica
        y_actual = nueva_h + grosor_linea_acento + padding_top
        
        bbox_hash = draw.textbbox((0, 0), hashtag_texto, font=font_hashtag)
        w_hash = bbox_hash[2] - bbox_hash[0]
        x_hash = (ANCHO_CANVAS - w_hash) // 2
        draw.text((x_hash, y_actual), hashtag_texto, font=font_hashtag, fill=COLOR_ACENTO)
        
        y_actual += tamano_hashtag + espacio_entre_hash_y_titulo
        
        for linea in lineas:
            bbox_linea = draw.textbbox((0, 0), linea, font=font_titular)
            w_linea = bbox_linea[2] - bbox_linea[0]
            x_linea = (ANCHO_CANVAS - w_linea) // 2
            
            draw.text((x_linea + 3, y_actual + 3), linea, font=font_titular, fill=(0, 0, 0, 150))
            draw.text((x_linea, y_actual), linea, font=font_titular, fill=(255, 255, 255, 255))
            
            y_actual += tamano_titular + interlineado
            
        img_final = img_final.convert("RGB")
        byte_arr = BytesIO()
        img_final.save(byte_arr, format='JPEG', quality=95)
        byte_arr.seek(0)
        return byte_arr

    except Exception as e:
        print(f"Error en diseño vertical dinámico: {e}")
        return None

# --- NÚCLEO DEL BOT ---
def ejecutar_bot():
    print("Paso 1: Iniciando Corporación Vanguardia Noticias...")
    noticias_frescas = []
    
    for url_feed in FEEDS_HUANUCO:
        try:
            feed = feedparser.parse(url_feed)
            nombre_fuente = feed.feed.title if 'title' in feed.feed else "Medio Local"
            for entry in feed.entries[:5]: 
                
                # Verificamos con el nuevo sistema de memoria absoluta
                if not noticia_ya_publicada(entry.link):
                    noticias_frescas.append({
                        'titulo': entry.title,
                        'link': entry.link,
                        'fuente': nombre_fuente,
                        'contexto': entry.get('summary', entry.get('description', ''))
                    })
        except Exception:
            continue
            
    if not noticias_frescas:
        print("--> 🛑 No hay noticias nuevas en este momento. Todas ya fueron publicadas.")
        return

    print(f"--> Se encontraron {len(noticias_frescas)} noticias nuevas. Analizando la mejor...")
    mejor_noticia = elegir_noticia_viral(noticias_frescas)
    print(f"--> ¡Noticia GANADORA!: {mejor_noticia['titulo']}")

    texto_post = generar_redaccion_profunda(mejor_noticia['titulo'], mejor_noticia['contexto'], mejor_noticia['fuente'])
    
    if not texto_post:
        print("❌ Todos los modelos agotaron su cuota por hoy.")
        return
    
    url_foto = extraer_imagen_desde_web(mejor_noticia['link'])
    
    # Pasamos el texto_post para sacar el hashtag correcto
    imagen_procesada = editar_imagen_con_texto(url_foto, mejor_noticia['titulo'], texto_post)

    print("Paso 6: Publicando en Facebook...")
    try:
        if imagen_procesada:
            graph.put_photo(image=imagen_procesada, message=texto_post, album_path='me/photos')
            print("¡LOGRADO! Post publicado con diseño gráfico moderno y adaptativo.")
        else:
            graph.put_object(parent_object='me', connection_name='feed', message=texto_post)
            print("¡LOGRADO! Post publicado sin imagen (Modo texto puro).")
            
        guardar_noticia_publicada(mejor_noticia['link'])
        print("--> ✅ Registro actualizado: Enlace guardado en publicadas.txt")
        
    except Exception as e:
        print(f"--- ERROR DE FACEBOOK --- \n{str(e)}")

# --- ARRANQUE ---
if __name__ == "__main__":
    ejecutar_bot()