# Archivo: Subir_Archivo.py
# Ruta: src\App\Subir_Archivo.py
# Lenguaje: Python con Flask
import os
from werkzeug.utils import secure_filename
import io
import ftplib
import tempfile
from flask import send_file, abort, redirect
import requests
from config import Config
from dotenv import load_dotenv
load_dotenv()
# /////////////////////////////////
#   Configuración Global
# ////////////////////////////////

# Base URL para acceso web
#BASE_URL = "https://files.sycelephant.com/"
BASE_URL = "https://file.sycelephant.com"

# /////////////////////////////////
#   Subir archivos por FTP
# ////////////////////////////////

def subir_archivo_ftp_desde_request(technicalSheet, item, carpeta_destino,carpeta):
    try:
        # Verificar si el archivo existe
        if not technicalSheet:
            return {"exito": False, "mensaje": "No se proporcionó ningún archivo"}
            
        # Verificar si es un PDF
        if not technicalSheet.filename.lower().endswith('.pdf'):
            return {"exito": False, "mensaje": "Solo se permiten archivos PDF"}
        
        # Generar nombre seguro para el archivo basado en el item
        nombre_archivo = secure_filename(f"{item.replace(' ', '_')}.pdf")
        
        # Guardar el archivo temporalmente
        temp_dir = tempfile.gettempdir()
        ruta_archivo_temp = os.path.join(temp_dir, nombre_archivo)
        technicalSheet.save(ruta_archivo_temp)
        
        # Conexión al servidor FTP utilizando variables de entorno
        host_ftp = os.getenv('FTP_HOST')
        usuario_ftp = os.getenv('FTP_USER')
        contraseña_ftp = os.getenv('FTP_PASS')
                
        conexion_ftp = ftplib.FTP(host_ftp)
        conexion_ftp.login(usuario_ftp, contraseña_ftp)
        
        # Cambiar al directorio de destino
        conexion_ftp.cwd(carpeta_destino)
        
        # Abrir el archivo en modo binario para lectura
        with open(ruta_archivo_temp, "rb") as archivo:
            # Subir el archivo al servidor FTP
            conexion_ftp.storbinary(f"STOR {nombre_archivo}", archivo)
        
        # Cerrar la conexión FTP
        conexion_ftp.quit()
        
        # Construir la URL para acceder al archivo
        url_archivo = f"{BASE_URL}{carpeta}{nombre_archivo}"
        
        # Eliminar el archivo temporal
        os.remove(ruta_archivo_temp)
        
        return {
            "exito": True, 
            "mensaje": f"Archivo '{nombre_archivo}' subido exitosamente a {host_ftp}/{carpeta_destino}",
            "nombre_archivo": nombre_archivo,
            "url_web": url_archivo
        }

    except Exception as e:
        # Si hay un error, intentar eliminar el archivo temporal si existe
        if 'ruta_archivo_temp' in locals() and os.path.exists(ruta_archivo_temp):
            os.remove(ruta_archivo_temp)
        
        return {"exito": False, "mensaje": f"Error al subir el archivo: {str(e)}"}
# /////////////////////////////////
#   Visualizar archivos PDF desde el servidor
# ////////////////////////////////

def view_pdf_file(filename_or_url):
    """
    Visualiza un archivo PDF específico desde el servidor remoto.
    
    Args:
        filename_or_url: Nombre del archivo PDF o URL completa
        
    Returns:
        Flask response: Envía el archivo para visualización o redirecciona a su URL
    """
    try:
        
        # Determinar si es una URL completa o solo un nombre de archivo
        if filename_or_url.startswith('http'):
            # Es una URL completa
            url = filename_or_url
            filename = url.split('/')[-1]  # Obtiene el nombre del archivo desde la URL
        else:
            # Es solo un nombre de archivo, construir URL completa
            filename = filename_or_url
            url = f"{BASE_URL}/static/pdf/Ventas/EUA/DMITEMS/BREAKER_CATALOG/{filename}"
          
        # Ruta temporal para guardar el archivo
        temp_file_path = os.path.join(tempfile.gettempdir(), filename)
        
        # Intentar descargar el archivo desde la URL
        response = requests.get(url, stream=True)
        
        if response.status_code == 200:
            with open(temp_file_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    f.write(chunk)
            
            # Envía el archivo como respuesta
            return send_file(
                temp_file_path,
                mimetype='application/pdf',
                as_attachment=False,
                download_name=filename
            )
        else:
            # Si no se puede descargar, redirigir a la URL
            return redirect(url)
        
    except Exception as e:
        print(f"Error al visualizar el PDF {filename_or_url}: {e}")
        # En caso de error, intentar redirigir directamente a la URL
        if filename_or_url.startswith('http'):
            return redirect(filename_or_url)
        else:
            abort(404)

# /////////////////////////////////
#   Verificar archivos en el servidor y actualizar tabla
# ////////////////////////////////
def verificar_actualizar_archivos(tabla, campo_id, campo_url, update_function, ruta_remota, search_function_name, search_function=None, module_path=None, base_url=BASE_URL, subfolder=None,carpeta=None):
    """
    Verifica la existencia de archivos en el servidor FTP y actualiza una tabla con las URLs.
    
    Args:
        tabla: Nombre de la tabla en la base de datos a consultar
        campo_id: Nombre del campo que contiene el identificador del registro
        campo_url: Nombre del campo que contiene la URL del archivo
        update_function: Función para actualizar el registro en la base de datos
        ruta_remota: Ruta en el servidor donde se buscarán los archivos
        search_function: Función para obtener los items (si es None, se importará dinámicamente)
        module_path: Ruta al módulo donde se encuentra la función de búsqueda
        search_function_name: Nombre de la función a importar del módulo (por defecto "searchitems")
        base_url: URL base para construir las URLs web (por defecto usa BASE_URL global)
        subfolder: Subcarpeta específica dentro de ruta_remota (opcional)
        
    Returns:
        dict: Diccionario con resultado de la operación
    """
    try:
        # Si no se proporciona search_function, importamos dinámicamente
        if search_function is None:
            if module_path is None:
                # Módulo por defecto si no se proporciona
                module_path = "Consultas_SQL.Ventas.VentasEUA.DataMaster.DMBreakerProtectionTypeSQL"
            
            try:
                # Importamos el módulo dinámicamente
                import importlib
                print(f"Importando dinámicamente desde: {module_path}")
                module = importlib.import_module(module_path)
                
                # Obtenemos la función del módulo
                search_function = getattr(module, search_function_name)
                print(f"Función importada: {search_function.__name__} desde {module.__name__}")
            except (ImportError, AttributeError) as import_error:
                print(f"Error importando función de búsqueda: {str(import_error)}")
                return {"exito": False, "mensaje": f"Error importando función de búsqueda: {str(import_error)}"}
        
        # Agregamos logs para depuración
        print(f"Iniciando verificación de archivos en tabla {tabla}")
        print(f"Ruta remota: {ruta_remota}")
        
        # Consultamos los registros de la tabla usando la función proporcionada
        items = search_function()
        print(f"Items encontrados: {len(items)}")
        
        if not items:
            return {"exito": False, "mensaje": f"No se encontraron datos en la tabla {tabla}."}
        
        # Imprimir primeros 3 items para depuración
        print(f"Muestra de items: {items[:3] if len(items) >= 3 else items}")
        
        # Ajustar ruta completa si hay subcarpeta
        if subfolder:
            ruta_completa = os.path.join(ruta_remota, subfolder).replace('\\', '/')
        else:
            ruta_completa = ruta_remota
        
        print(f"Ruta completa: {ruta_completa}")
        
        # Conexión al servidor FTP utilizando variables de entorno
        host_ftp = os.getenv('FTP_HOST')
        usuario_ftp = os.getenv('FTP_USER')
        contraseña_ftp = os.getenv('FTP_PASS')
        
        try:
            # Establecer conexión FTP
            print(f"Conectando a {host_ftp}")
            ftp = ftplib.FTP(host_ftp)
            ftp.login(usuario_ftp, contraseña_ftp)
            
            # Listar archivos en el directorio remoto
            try:
                # Cambiar al directorio para listar archivos
                ftp.cwd(ruta_completa)
                archivos_remotos = ftp.nlst()
                print(f"Archivos encontrados en servidor: {len(archivos_remotos)}")
                print(f"Primeros 5 archivos: {archivos_remotos[:5] if len(archivos_remotos) >= 5 else archivos_remotos}")
            except ftplib.error_perm as perm_error:
                print(f"Error de permisos al listar directorio: {str(perm_error)}")
                return {"exito": False, "mensaje": f"El directorio {ruta_completa} no existe en el servidor o no hay permisos."}
            
            actualizados = 0
            no_encontrados = 0
            
            # Procesar cada ítem
            for item in items:
                # Manejo seguro del diccionario
                item_id = item.get(campo_id, "")  # Usar .get() para un acceso seguro al diccionario
                item_url = item.get(campo_url)    # Usar .get() para un acceso seguro al diccionario
                
                if not item_id:
                    print(f"Item sin ID válido: {item}")
                    continue
                
                # Crear el nombre de archivo basado en el ID
                nombre_archivo = f"{item_id.replace(' ', '_')}.pdf"
                print(f"Verificando archivo: {nombre_archivo}")
                
                # Verificar si el archivo existe en el servidor
                if nombre_archivo in archivos_remotos:
                    print(f"Archivo encontrado en servidor: {nombre_archivo}")
                    
                    # Construir la URL completa
                    # Determinar la ruta web basada en la estructura del servidor
                    # Esto puede necesitar ajuste según tu estructura específica
                    path_web = carpeta  # Ajustar según tu estructura
                    url_completa = f"{base_url}{path_web}/{nombre_archivo}"
                    
                    print(f"URL construida: {url_completa}")
                    print(f"URL actual: {item_url}")
                    
                    # Actualizar solo si la URL actual es diferente o es None
                    if item_url != url_completa:
                        print(f"Actualizando {item_id} con URL: {url_completa}")
                        update_function(item_id, url_completa)
                        actualizados += 1
                else:
                    print(f"Archivo NO encontrado en servidor: {nombre_archivo}")
                    
                    # Actualizar con valor nulo si actualmente tiene un valor
                    if item_url is not None and item_url != "":
                        print(f"Limpiando URL para {item_id}")
                        update_function(item_id, None)
                        no_encontrados += 1
            
            # Cerrar conexión FTP
            ftp.quit()
            
            return {
                "exito": True, 
                "mensaje": f"Verificación completada. Actualizados: {actualizados}, No encontrados: {no_encontrados}",
                "actualizados": actualizados,
                "no_encontrados": no_encontrados
            }
            
        except Exception as ftp_error:
            print(f"Error de conexión FTP: {str(ftp_error)}")
            return {"exito": False, "mensaje": f"Error de conexión FTP: {str(ftp_error)}"}
        
    except Exception as e:
        print(f"Error general: {str(e)}")
        import traceback
        print(traceback.format_exc())
        return {"exito": False, "mensaje": f"Error: {str(e)}"}