import json
import os
import shutil
import paramiko
from cnxpdo import get_connection  # Importa la conexión a la base de datos
from fastapi import UploadFile
from dotenv import load_dotenv


script_dir = os.path.dirname(os.path.abspath(__file__))  # Directorio del script
crm_dir = os.path.dirname(script_dir)  # Sube un nivel hasta crm
env_path = os.path.join(crm_dir, "configuraciones", ".env")  # Ahora sí apunta bien

load_dotenv(env_path)


def updateLandingImage(id: int, file: UploadFile, file_name: str, file_type: str, vista: str):
    # =============================
    # 📌 Validaciones iniciales
    # =============================
    if not file or not file_name or not file_type or not vista:
        return {"success": False, "message": "Faltan datos necesarios para procesar la imagen."}

    allowed_types = [
        'image/jpeg', 'image/png', 'image/jpg', 'image/gif', 'image/svg+xml',  # Imágenes
        'video/mp4', 'video/mov'  # Videos
    ]

    if file_type not in allowed_types:
        return {"success": False, "message": "Formato de archivo no permitido."}

    try:
        file.file.seek(0)
        file_content = file.file.read()
        if not file_content:
            return {"success": False, "message": "El archivo está vacío o no se pudo leer."}
    except Exception as e:
        return {"success": False, "message": "Error al leer el archivo."}

    # Calcular tamaño del archivo
    file_size = len(file_content)

    # Limpiar y validar nombre de vista para usar como carpeta
    vista_name = vista.strip().lower().replace(' ', '_').replace('-', '_')
    if not vista_name:
        return {"success": False, "message": "La vista proporcionada no es válida."}

    # =============================
    # 📌 Configuración SFTP
    # =============================
    # server = '10.31.105.4'
    # username = 'userware_prod'
    # password = '5g54aMuY3Z!'
    
    # Crear ruta con carpeta por vista
    # base_folder = "/var/www/dev.imparables.cic-ware.com/assets/images/"
    # remote_folder = f"{base_folder}{vista_name}/"
    
    server = os.getenv('ftp_server')
    username = os.getenv('ftp_user_name')
    password = os.getenv('ftp_user_pass')
    base_folder = os.getenv('ftp_remote_folder')
    port = 22

    """ remote_folder = f"{base_folder}{vista_name}/"
    remote_file_path = f"{remote_folder}{file_name}" """

    # Autenticación: password o llave
    ftp_pass = os.getenv('FTP_PASS_ALT') or ""
    key_path = os.getenv('ftp_key_path', '/home/ubuntu/admin-access.pem')
    key_pass = os.getenv('ftp_key_pass') or None
    use_password = bool(ftp_pass.strip())
    

    if not use_password:
        print(f"   - Key Path: {'✅ OK' if key_path else '❌ VACÍO'} ({key_path})")

    if not server:
        return {"success": False, "message": "Variable de entorno 'ftp_server' no está configurada"}
    if not username:
        return {"success": False, "message": "Variable de entorno 'ftp_user_name' no está configurada"}
    if not base_folder:
        return {"success": False, "message": "Variable de entorno 'ftp_remote_folder' no está configurada"}
    if not use_password and not os.path.isfile(key_path):
        return {"success": False, "message": f"No se encontró la llave privada en '{key_path}'"}

    # ---- Armar rutas ----
    remote_folder = f"{base_folder.rstrip('/')}/{vista_name}/"
    remote_file_path = f"{remote_folder}{file_name}"
    
    print(f"🎯 [DEBUG] Remote folder: {remote_folder}")
    print(f"🎯 [DEBUG] Remote file path: {remote_file_path}")

    # ---- Pre-chequeo de red para 22/tcp ----
    print(f"🌐 [CHECK] Verificando conectividad TCP a {server}:{port} ...")
    try:
        with socket.create_connection((server, port), timeout=5):
            pass
    except Exception as e:
        return {"success": False, "message": f"No hay conectividad TCP al puerto {port} de {server}: {e}"}
    print("🌐 [CHECK] OK")
    
    # ---- Conexión SSH + SFTP ----
    client = None
    sftp = None
    try:
        print(f"🔐 [SFTP] Conectando a {server}:{port} como {username} con {'PASSWORD' if use_password else 'KEY'}")
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        if use_password:
            # ---- AUTENTICACIÓN POR CONTRASEÑA ----
            client.connect(
                server,
                port=port,
                username=username,
                password=ftp_pass,
                look_for_keys=False,
                allow_agent=False,
                timeout=15,
                banner_timeout=15,
                auth_timeout=15,
            )
        else:
            # ---- AUTENTICACIÓN POR LLAVE (carga explícita) ----
            pkey = None
            last_err = None
            for loader in (
                lambda: paramiko.RSAKey.from_private_key_file(key_path, password=key_pass),
                lambda: paramiko.Ed25519Key.from_private_key_file(key_path, password=key_pass),
                lambda: paramiko.ECDSAKey.from_private_key_file(key_path, password=key_pass),
                lambda: paramiko.DSSKey.from_private_key_file(key_path, password=key_pass),
            ):
                try:
                    pkey = loader()
                    break
                except Exception as e:
                    last_err = e
            if pkey is None:
                return {"success": False, "message": f"No se pudo cargar la llave privada '{key_path}': {last_err}"}

            client.connect(
                server,
                port=port,
                username=username,
                pkey=pkey,
                look_for_keys=False,
                allow_agent=False,
                timeout=15,
                banner_timeout=15,
                auth_timeout=15,
            )

        transport = client.get_transport()
        if transport:
            transport.set_keepalive(30)

        sftp = client.open_sftp()
        print("✅ [SFTP] Sesión abierta")

        # Crear estructura de directorios recursivamente
        remote_dir = remote_folder.rstrip("/")
        parts = remote_dir.split("/")
        cur = ""
        for p in parts:
            if not p:
                continue
            cur = f"{cur}/{p}"
            try:
                sftp.stat(cur)
            except IOError:
                print(f"📁 [SFTP] Creando directorio: {cur}")
                sftp.mkdir(cur)

        # Eliminar archivo existente si existe
        try:
            sftp.stat(remote_file_path)
            sftp.remove(remote_file_path)
            print(f"🗑️ [SFTP] Archivo existente eliminado: {remote_file_path}")
        except IOError:
            pass

        # Subir el nuevo archivo
        print(f"📤 [SFTP] Subiendo {file_name} ...")
        with sftp.open(remote_file_path, "wb") as f:
            f.write(file_content)
        print(f"✅ [SFTP] Archivo subido a: {remote_file_path}")

    except paramiko.AuthenticationException as auth_error:
        return {"success": False, "message": f"Error de autenticación SFTP: {auth_error}"}
    except paramiko.SSHException as ssh_error:
        return {"success": False, "message": f"Error SSH: {ssh_error}"}
    except socket.error as socket_error:
        return {"success": False, "message": f"Error de red al conectar SFTP: {socket_error}"}
    except Exception as e:
        return {"success": False, "message": f"Error inesperado al subir archivo: {e} - Tipo: {type(e).__name__}"}
    finally:
        if sftp:
            try:
                sftp.close()
            except Exception:
                pass
        if client:
            try:
                client.close()
            except Exception:
                pass

    # =============================
    # 📌 Actualización en Base de Datos
    # =============================
    try:
        conexionBD = get_connection()
        if not conexionBD:
            return {"success": False, "message": "Error de conexión a la base de datos."}

        cursor = conexionBD.cursor()
        
        # Verificar para variable de entorno.
        app_url = os.getenv('DEV_IMAGE_PATH')
        if not app_url:
            return {'success': False, 'message': 'Variable de entorno DEV_IMAGE_PATH no está configurada.'}
        
        app_url = app_url.rstrip('/')
        image_path = f"{app_url}/assets/images/{vista_name}/{file_name}"
        
        query = "UPDATE ctr_assets_landing SET tipo = %s, ruta = %s, tamano = %s WHERE id = %s"
        cursor.execute(query, (file_type, image_path, file_size, id))
        conexionBD.commit()
        cursor.close()
        conexionBD.close()
        
        print(f"💾 [DB] Ruta y tamaño actualizados en BD: {image_path} ({file_size} bytes)")
        
    except Exception as e:
        return {"success": False, "message": f"Error al actualizar la base de datos: {e}"}

    # Determinar tipo de archivo para mensaje
    is_video = file_type.startswith('video/')
    media_type = "Video" if is_video else "Imagen"

    return {
        "success": True, 
        "message": f"{media_type} actualizado correctamente.",
        "data":{
            "id": id,
            "tipo": file_type,
            "nombre": file_name,
            "tamano": file_size,
            "vista": vista_name,
            "ruta": f"/assets/images/{vista_name}/{file_name}"
        }
    }

def obtenerAssetsLanding():
    conexionBD = get_connection()
    if conexionBD is None:
        return {"success": 0, "message": "Error de conexión"}
    
    try:
        cursor = conexionBD.cursor(dictionary=True)
        query = "SELECT id, vista, seccion, tipo, ruta, tamano FROM ctr_assets_landing WHERE 1"
        cursor.execute(query)
        assets = cursor.fetchall()
        
        # Sustituir valores nulos por cadenas vacías
        for asset in assets:
            for key, value in asset.items():
                if value is None:
                    asset[key] = ""
        
        return {"success": 1, "message": "Assets obtenidos correctamente", "data": assets}
    
    except Exception as e:
        return {"success": 0, "message": f"Error al obtener los assets: {str(e)}"}
    
    finally:
        cursor.close()
        conexionBD.close()






def update_Landing_Texts(data: dict):
    id = data.get('id')
    titulo = data.get('titulo')
    cuerpo = data.get('cuerpo')
    
    # Validar que el ID sea obligatorio
    if not id:
        return {
            "success": False,
            "message": "Falta el campo obligatorio: id"
        }
    
    # Validar que al menos uno de los campos tenga valor (no None, no vacío)
    titulo_valido = titulo is not None and titulo != ""
    cuerpo_valido = cuerpo is not None and cuerpo != ""
    
    if not titulo_valido and not cuerpo_valido:
        return {
            "success": False,
            "message": "Debe proporcionar al menos un campo con valor para actualizar (titulo o cuerpo)"
        }

    conexionBD = get_connection()
    if conexionBD is None:
        return {
            "success": False, 
            "message": "Error de conexión a la base de datos"
        }

    try:
        cursor = conexionBD.cursor()
        
        # PRIMERO: Verificar que el registro existe antes del UPDATE
        check_query = "SELECT ctr_texts_id FROM ctr_texts_landing WHERE ctr_texts_id = %s"
        cursor.execute(check_query, (id,))
        registro_existe = cursor.fetchone()
        
        print(f"🔍 DEBUG - ID recibido: {id}")
        print(f"🔍 DEBUG - Registro existe: {registro_existe is not None}")
        
        if not registro_existe:
            return {
                "success": False,
                "message": f"No existe ningún registro con el ID {id} en la base de datos"
            }
        
        # Construir la query dinámicamente solo con los campos que tienen valor
        campos_actualizar = []
        valores = []
        campos_enviados = []
        
        if titulo_valido:
            campos_actualizar.append("title = %s")
            valores.append(titulo)
            campos_enviados.append("titulo")
            
        if cuerpo_valido:
            campos_actualizar.append("body = %s")
            valores.append(cuerpo)
            campos_enviados.append("cuerpo")
        
        # Agregar el ID al final para la cláusula WHERE
        valores.append(id)
        
        # Construir la query final
        query = f"""
            UPDATE ctr_texts_landing 
            SET {', '.join(campos_actualizar)}
            WHERE ctr_texts_id = %s
        """
        
        print(f"🔍 DEBUG - Query generada: {query}")
        print(f"🔍 DEBUG - Valores: {valores}")
        
        # Ejecutar la query
        cursor.execute(query, valores)
        conexionBD.commit()
        
        print(f"🔍 DEBUG - Filas afectadas: {cursor.rowcount}")
        
        # Verificar si se actualizó algún registro
        if cursor.rowcount == 0:
            return {
                "success": True,  # Cambio importante: True porque el registro existe
                "message": "No se encontraron registros para actualizar o no hubo cambios en los datos. Los valores enviados son idénticos a los existentes."
            }
        
        return {
            "success": True, 
            "message": f"Textos actualizados correctamente. Campos actualizados: {', '.join([campo.split(' = ')[0] for campo in campos_actualizar])}"
        }
    
    except Exception as e:
        return {
            "success": False, 
            "message": f"Error al actualizar los textos: {str(e)}"
        }

    finally:
        if cursor:
            cursor.close()
        if conexionBD:
            conexionBD.close()



def get_texts_landing():
    conexionBD = get_connection()
    if conexionBD is None:
        return {"success": False, "message": "Error de conexión"}
    
    try:
        cursor = conexionBD.cursor(dictionary=True)
        query = "SELECT ctr_texts_id, view, section, type, title, body FROM ctr_texts_landing WHERE 1"
        cursor.execute(query)
        datos_texts = cursor.fetchall()
        
        # Sustituir valores nulos por cadenas vacías
        for dato in datos_texts:
            for key, value in dato.items():
                if value is None:
                    dato[key] = ""
        
        return {"success": True, "message": "Datos obtenidos correctamente", "data": datos_texts}
    
    except Exception as e:
        return {"success": False, "message": f"Error al obtener los datos de assets: {str(e)}"}
    
    finally:
        cursor.close()
        conexionBD.close()



