"""
Servicio de sincronización de productos desde XML a Neo4j.
"""
import logging
import os
import time
import xml.etree.ElementTree as ET

import httpx
from rag_service.neo4j_client import neo4j_client
from ..models import SyncProductsResponse

logger = logging.getLogger(__name__)

_URL_PRODUCTS = os.getenv("MARCIMEX_XML_URL", "https://www.marcimex.com/XMLData/botai.xml")
_PROMOTIONS_URL = os.getenv("MARCIMEX_PROMOTIONS_URL", "https://www.marcimex.com/XMLData/catalogo_bot.xml")
_G_NS = "{http://base.google.com/ns/1.0}"


def _parse_products_xml(xml_content: str) -> list[dict]:
    """Parsea el XML de productos y retorna lista de dicts."""
    root = ET.fromstring(xml_content)
    products = []
    for item in root.findall("item"):
        def get_text(tag: str) -> str | None:
            elem = item.find(tag)
            if elem is not None and elem.text:
                return elem.text.strip()
            return None

        products.append({
            "product_id": get_text("product_id"),
            "sku_id": get_text("sku_id"),
            "title": get_text("title"),
            "description": get_text("product_description"),
            "summary": get_text("summary"),
            "category": get_text("category"),
            "global_category": get_text("global_category"),
            "sub_category": get_text("sub_category"),
            "product_type": get_text("product_type"),
            "brand": get_text("brand"),
            "rpx_code": get_text("rpx_code"),
            "link": get_text("link"),
            "image_link": get_text("image_link"),
            "price": get_text("product_price_with_tax"),
            "in_stock": get_text("in_stock"),
            "availability": get_text("availability"),
            "status": get_text("product_status"),
            "color": get_text("color"),
            "specifications": get_text("specifications"),
        })
    return products


def _parse_promo_ids_xml(xml_content: str) -> list[str]:
    """Parsea el XML de promociones y retorna lista de product IDs."""
    root = ET.fromstring(xml_content)
    channel = root.find("channel")
    items = channel.findall("item") if channel is not None else root.findall(".//item")
    promo_ids = []
    for item in items:
        pid_elem = item.find(f"{_G_NS}product_id")
        if pid_elem is not None and pid_elem.text:
            pid = pid_elem.text.strip()
            if pid:
                promo_ids.append(pid)
    return promo_ids


async def sync_products() -> SyncProductsResponse:
    """
    Sincroniza productos desde XML a Neo4j e incluye actualización de promociones.

    - Si la BD está vacía: sube todos los productos con estado 'nuevo'
    - Si ya hay datos: sincronización incremental
    """
    start_time = time.time()
    logger.info("🚀 === INICIO sync_products ===")
    logger.info(f"🗄️ Usando base de datos: {neo4j_client.get_current_database()}")

    # 0. Inicializar campo promotion en productos existentes sin él
    logger.info("🔧 PASO 0: Inicializando campo promotion en productos existentes...")
    updated = neo4j_client.initialize_promotion_field()
    logger.info(f"🏷️ Campo promotion inicializado en {updated} productos existentes")

    # 1. Descargar y parsear XML de productos
    logger.info(f"🌐 PASO 1: Descargando XML desde '{_URL_PRODUCTS}'...")
    t0 = time.time()
    async with httpx.AsyncClient(timeout=120.0) as client:
        response = await client.get(_URL_PRODUCTS)
        response.raise_for_status()
        xml_content = response.text
    logger.info(f"✅ XML descargado en {time.time() - t0:.2f}s ({len(xml_content)} bytes)")

    products = _parse_products_xml(xml_content)
    logger.info(f"📦 XML parseado: {len(products)} productos encontrados para sincronizar")

    # 2. Sincronizar con Neo4j
    logger.info(f"🌿 PASO 2: Sincronizando {len(products)} productos con Neo4j...")
    t0 = time.time()
    result = neo4j_client.sync_products_from_xml(products)
    logger.info(f"✅ Sincronización Neo4j completada en {time.time() - t0:.2f}s: {result}")

    # 3. Actualizar promociones
    promo_count = 0
    try:
        logger.info(f"🏷️ PASO 3: Descargando XML de promociones desde '{_PROMOTIONS_URL}'...")
        t0 = time.time()
        async with httpx.AsyncClient(timeout=60.0) as client:
            promo_response = await client.get(_PROMOTIONS_URL)
            promo_response.raise_for_status()
            promo_xml = promo_response.text
        logger.info(f"✅ XML de promociones descargado en {time.time() - t0:.2f}s ({len(promo_xml)} bytes)")

        promo_ids = _parse_promo_ids_xml(promo_xml)
        logger.info(f"🏷️ Productos en promoción encontrados en XML: {len(promo_ids)}")

        neo4j_client.reset_all_promotions()
        promo_count = neo4j_client.set_promotions_by_ids(promo_ids)
        logger.info(f"✅ Promociones actualizadas: {promo_count} productos marcados con promotion=true")
        if promo_count > 0:
            promo_products = neo4j_client.execute_query(
                "MATCH (p:Product) WHERE p.promotion = true "
                "OPTIONAL MATCH (p)-[:BELONGS_TO]->(c:Category) "
                "OPTIONAL MATCH (p)-[:MADE_BY]->(b:Brand) "
                "RETURN p.id AS id, p.name AS name, b.name AS brand, "
                "c.name AS category, p.price AS price "
                "ORDER BY p.name"
            )
            logger.info(f"🏷️  PRODUCTOS EN PROMOCIÓN ({promo_count} en Neo4j / {len(promo_ids)} IDs en XML):")


    except Exception as promo_err:
        logger.warning(f"⚠️ No se pudo actualizar promociones: {promo_err}")

    result["promotions_updated"] = promo_count
    elapsed = time.time() - start_time
    logger.info(
        f"🏁 === FIN sync_products. Tiempo total: {elapsed:.2f}s | "
        f"productos={len(products)}, promociones={promo_count} ==="
    )
    return SyncProductsResponse(**result)
