# Archivo: RecepcionCotizSQL.py
# Ruta: src\Consultas_SQL\Ventas\Cotiz\RecepcionCotizSQL.py

import pyodbc
import logging
from typing import Dict, List, Optional
from Consultas_SQL.conexion import get_connection

logger = logging.getLogger('recepcion_cotizacion_sql')

# =========================================================================================
# FUNCIÓN 1: BUSCAR COTIZACIÓN COMPLETA
# =========================================================================================
def buscar_cotizacion_completa(cotizacion_id: str) -> Optional[Dict]:
    """
    Busca los datos de la oportunidad, las líneas de ingeniería y el estado.
    
    Args:
        cotizacion_id (str): ID de la oportunidad (Ej: 123456-1)
    
    Returns:
        Dict: Datos de la oportunidad y las líneas o None.
    """
    # 1. Dividir el ID para obtener OpportunityNumber y Version
    try:
        op_number, version = cotizacion_id.split('-')
        op_number = op_number.strip()
        version = int(version.strip())
    except ValueError:
        logger.error(f"Formato de cotizacion_id inválido: {cotizacion_id}")
        return None

    # Consulta para obtener los datos de la Oportunidad (Q_OpportunityCRM)
    # y las Líneas de Cotización (Q_QuotationLines)
    # Esta consulta necesita ser compleja para unir las 3-4 tablas necesarias.
    query = """
        SELECT
            T1.CRM_OpportunityNumber,
            T1.Version,
            T1.CRM_ContactName,
            T1.CRM_ContactEmail,
            T1.Status AS StatusVenta,
            -- Asumimos una tabla de estado de ingeniería
            T2.StatusIngenieria, 
            T3.Partnum,
            T3.Description,
            T3.Quantity,
            T3.UnitPriceIngenieria, -- Precio que puso Ingeniería
            T3.DiscountVenta,       -- Descuento que puede modificar Venta
            T3.FinalPrice,
            -- Campos financieros ya calculados (si existen)
            T1.PrecioLista,
            T1.PrecioVentaIVA,
            T1.TiempoEntrega,
            T1.UnidadTiempo,
            T1.TerminosIngenieria -- Términos de Ingeniería
        FROM Q_OpportunityCRM T1
        LEFT JOIN Q_QuotationHead T2 ON T1.CRM_OpportunityID = T2.CRM_OpportunityID 
        LEFT JOIN Q_QuotationLines T3 ON T2.QuotationID = T3.QuotationID 
        WHERE 
            T1.CRM_OpportunityNumber = ? AND T1.Version = ? AND T1.Active = 1
            AND T2.StatusIngenieria IS NOT NULL -- Solo cotizaciones que han pasado por ingeniería
        ORDER BY T3.LineNum ASC
    """

    conn = get_connection()
    if not conn: raise ConnectionError("No se pudo establecer conexión con la base de datos")

    try:
        with conn:
            cursor = conn.cursor()
            cursor.execute(query, (op_number, version))
            
            columns = [column[0] for column in cursor.description]
            rows = cursor.fetchall()
            
            if not rows:
                logger.warning(f"No se encontraron datos para Cotización ID: {cotizacion_id}")
                return None
            
            # Procesar el resultado: un solo encabezado, múltiples líneas
            header = {}
            lines = []
            
            for row in rows:
                data = dict(zip(columns, row))
                if not header:
                    # Rellenar el encabezado solo una vez
                    header = {k: data[k] for k in data if k not in ['Partnum', 'Description', 'Quantity', 'UnitPriceIngenieria', 'DiscountVenta', 'FinalPrice']}
                    header['cotizacion_id'] = cotizacion_id
                    header['lineas'] = lines
                    
                # Agregar la línea a la lista
                lines.append({
                    'Partnum': data['Partnum'],
                    'Description': data['Description'],
                    'Quantity': data['Quantity'],
                    'UnitPriceIngenieria': data['UnitPriceIngenieria'],
                    'DiscountVenta': data['DiscountVenta'],
                    'FinalPrice': data['FinalPrice']
                })

            return header

    except pyodbc.Error as e:
        logger.error(f"Error de base de datos al buscar cotización: {str(e)}")
        raise
    except Exception as e:
        logger.error(f"Error inesperado en buscar_cotizacion_completa: {str(e)}")
        raise
    finally:
        if conn: conn.close()

# =========================================================================================
# FUNCIÓN 2: ACTUALIZAR LÍNEAS DE COTIZACIÓN
# =========================================================================================
def actualizar_lineas_cotizacion(cotizacion_id: str, lineas: List[Dict], user_id: int) -> Dict:
    """Actualiza campos editables (ej. Descuento) en Q_QuotationLines."""
    # Simulación de la función: Asume que las líneas se actualizan en un lote
    if not lineas:
        return {'success': True, 'message': 'No hay líneas para actualizar'}
        
    try:
        # Obtener nombre de usuario para auditoría
        from .CotizEspSolicitudSQL import obtener_nombre_usuario
        user_name = obtener_nombre_usuario(user_id)
        
        # Lógica de actualización de lotes...
        logger.info(f"Actualizando {len(lineas)} líneas para {cotizacion_id} por {user_name}")
        # ... (código SQL para UPDATE en lote)
        
        return {'success': True, 'message': 'Líneas actualizadas'}
    except Exception as e:
        logger.error(f"Error al actualizar líneas de cotización: {str(e)}")
        return {'success': False, 'message': str(e)}
        
# =========================================================================================
# FUNCIÓN 3: ACTUALIZAR CÁLCULO FINANCIERO
# =========================================================================================
def actualizar_calculo_financiero(cotizacion_id: str, financieros: Dict, user_id: int) -> Dict:
    """Actualiza la sección financiera en Q_OpportunityCRM (o Q_QuotationHead)."""
    # Asume que estos campos se guardan en Q_OpportunityCRM
    query = """
        UPDATE Q_OpportunityCRM
        SET 
            DiscountPorcentaje = ?,
            IncludesIVA = ?,
            PrecioVentaIVA = ?,
            UpdatedBy = ?,
            UpdatedAt = GETDATE()
        WHERE CRM_OpportunityID = ? -- Asumiendo que el ID de la oportunidad es el cotizacion_id
    """
    
    conn = get_connection()
    if not conn: return {'success': False, 'message': 'Error de conexión a BD'}

    try:
        from .CotizEspSolicitudSQL import obtener_nombre_usuario
        user_name = obtener_nombre_usuario(user_id)
        
        with conn:
            cursor = conn.cursor()
            cursor.execute(query, (
                financieros['descuento'],
                financieros['incluye_iva'],
                financieros['precio_final_con_iva'],
                user_name,
                cotizacion_id
            ))
            conn.commit()
            
            if cursor.rowcount == 0:
                 return {'success': False, 'message': 'Oportunidad no encontrada para actualización financiera'}
            
            logger.info(f"Datos financieros actualizados para {cotizacion_id}")
            return {'success': True}
    except pyodbc.Error as e:
        logger.error(f"Error de BD al actualizar financieros: {str(e)}")
        return {'success': False, 'message': 'Error de base de datos'}
    finally:
        if conn: conn.close()

# =========================================================================================
# FUNCIÓN 4: ACTUALIZAR TIEMPO Y CONDICIONES
# =========================================================================================
def actualizar_tiempo_y_condiciones(cotizacion_id: str, tiempo_condiciones: Dict, user_id: int) -> Dict:
    """Actualiza el tiempo de entrega y los términos técnicos en Q_OpportunityCRM."""
    query = """
        UPDATE Q_OpportunityCRM
        SET 
            TiempoEntrega = ?,
            UnidadTiempo = ?,
            TerminosVenta = ?, -- Nuevo campo para términos de Venta
            UpdatedBy = ?,
            UpdatedAt = GETDATE()
        WHERE CRM_OpportunityID = ?
    """
    
    conn = get_connection()
    if not conn: return {'success': False, 'message': 'Error de conexión a BD'}

    try:
        from .CotizEspSolicitudSQL import obtener_nombre_usuario
        user_name = obtener_nombre_usuario(user_id)
        
        with conn:
            cursor = conn.cursor()
            cursor.execute(query, (
                tiempo_condiciones['tiempo_ejecucion'],
                tiempo_condiciones['unidad_tiempo'],
                tiempo_condiciones['terminos_venta'],
                user_name,
                cotizacion_id
            ))
            conn.commit()
            
            if cursor.rowcount == 0:
                 return {'success': False, 'message': 'Oportunidad no encontrada para actualización de condiciones'}
            
            logger.info(f"Tiempo y condiciones actualizados para {cotizacion_id}")
            return {'success': True}
    except pyodbc.Error as e:
        logger.error(f"Error de BD al actualizar tiempo y condiciones: {str(e)}")
        return {'success': False, 'message': 'Error de base de datos'}
    finally:
        if conn: conn.close()

# =========================================================================================
# FUNCIÓN 5: FINALIZAR COTIZACIÓN Y ENVIAR
# =========================================================================================
def finalizar_cotizacion_y_enviar(cotizacion_id: str, user_id: int, data: Dict) -> Dict:
    """
    Marca el estado final de la cotización, genera el PDF y registra el evento.
    
    Nota: La generación de PDF con Puppeteer/Node.js debería llamarse aquí.
    """
    try:
        # 1. Actualizar estado de Oportunidad a 'ENVIADA_A_CLIENTE'
        # Simulación de la actualización de estado...
        
        # 2. Generación del PDF (integración con puppeteer_pdf/generate_pdf.js)
        # Aquí se ejecutaría el script de Node.js con los datos de la cotización
        pdf_url = generar_pdf_final_cotizacion(cotizacion_id, data)
        
        # 3. Registrar el evento de envío en la tabla de auditoría
        # Simulación de registro...
        
        logger.info(f"Cotización {cotizacion_id} marcada como ENVIADA_A_CLIENTE y PDF generado: {pdf_url}")
        return {'success': True, 'pdf_url': pdf_url}
    except Exception as e:
        logger.error(f"Error al finalizar cotización y generar PDF: {str(e)}")
        return {'success': False, 'message': str(e)}

def generar_pdf_final_cotizacion(cotizacion_id: str, data: Dict) -> str:
    """Simula la generación de PDF final (debería llamar a Node.js/Puppeteer)."""
    # Lógica que llama a:
    # 1. Crear HTML final con datos (incluye financieras)
    # 2. Ejecutar comando Node.js/Puppeteer para renderizar y guardar en la ruta estática
    # 3. Registrar PDF en DocsManagement
    
    return f"https://sycelephant.com/static/pdfs/cotiz/{cotizacion_id}_final.pdf"