<?php namespace App\Http\Controllers;

use DB;
use Session;
use Request;  
use App\Custom\SQLConnection;
use App\Custom\Misc;
use stdClass;


class PromptsController extends Controller  
{

    /**
    * Maneja el proceso de obtener y filtrar los datos de prompts junto con ratios financieros
    *
    * Esta funcion obtiene datos de prompts y los filtra para incluir solo los prompts activos 
    * Tambien obtiene varios ratios financieros para mostrar en la vista
    *
    * @return View La vista 'seccion-prompts/seccion_prompts' con los datos filtrados de los prompts y los ratios financieros
    */
    public function seccionPrompts(){        
        // Se obtiene los datos de los prompts 
        $datos_prompt = SQLConnection::backendStoreProcedure('gestor_prompts', ['seleccionar', null, null, null, null, null, null, null, null]);   

        /* $estadoPrompt = 1;
           
        $datos_prompt = array_filter($datos_prompt, function($prompt) use ($estadoPrompt) {
            return isset($prompt->active) && $prompt->active === $estadoPrompt;
        }); */

        $datos_proveedores = SQLConnection::backendStoreProcedure('gestor_ai_provider', ['ALL_PROVIDERS']);
        $modelosAi = SQLConnection::backendStoreProcedure('gestor_ai_model', ['ALL_AI_MODELS']);
        $tipoPrompts =  SQLConnection::backendStoreProcedure('gestor_prompt_scope', ['ALL_PROMPT_SCOPE']);
        $claes = SQLConnection::backendStoreProcedure('clae_agrupacion',[]);        
                     
        // Se obtiene ratios financieros
        $ratios_cuentas = SQLConnection::backendStoreProcedure('abm_nombre_ratios', array('SELECT', NULL, NULL, 'CUENTAS'));        
        $ratios_financiero = SQLConnection::backendStoreProcedure('abm_nombre_ratios', array('SELECT', NULL, NULL, 'FINANCIERO'));
        $ratios_eficiencia = SQLConnection::backendStoreProcedure('abm_nombre_ratios', array('SELECT', NULL, NULL, 'EFICIENCIA'));
        $ratios_patrimonial = SQLConnection::backendStoreProcedure('abm_nombre_ratios', array('SELECT', NULL, NULL, 'PATRIMONIAL'));
        $ratios_rentabilidad = SQLConnection::backendStoreProcedure('abm_nombre_ratios', array('SELECT', NULL, NULL, 'RENTABILIDAD'));

        return view('seccion-prompts/seccion_prompts_newv2')->with(compact(
            'datos_prompt',
            'tipoPrompts',
            'datos_proveedores', 
            'ratios_cuentas', 
            'ratios_patrimonial', 
            'ratios_rentabilidad', 
            'ratios_financiero', 
            'ratios_eficiencia',
            'claes',
            'modelosAi'
        ));
    }

    /**
    * Guarda un prompt
    *
    * La funcion obtiene los datos del prompt, tambien realiza una verificacion para evitar la duplicacion del nombre del prompt 
    * La funcion tambien maneja ratios en el caso que el prompt sea de balances
    *
    * @return string JSON con el estado de la funcion:
    *                 - Si hay un error en los datos de entrada, se devuelve un JSON con el codigo de error y un mensaje 
    *                 - Si el nombre del prompt ya existe, se devuelve un JSON con el codigo de error 3 y un mensaje
    *                 - Si la funcion se ejecuta con exito, se devuelve un JSON con el código de error 0 y un mensaje de exito
    */
    public function guardarPrompts()
    {            
        $tipoPrompt = Request::input('tipo_prompt') ?? null;
        $tablaTipoPrompt = Request::input('tablaTipoPrompt') ?? null;
        $estadoPrompts = Request::input('estado_prompts') ?? null;
        $proveedorAi = Request::input('proveedor_ai') ?? null;
        $claes = Request::input('claes') ?? null; 
        $tipoCarga = Request::input('tipoCarga') ?? null;
        $pais = Request::input('pais') ?? null;                                      
        
        switch ($tipoPrompt) {
            case 1:
                $tipoPrompt = 'edicto';
                break;
            case 2:
                $tipoPrompt = 'balance';              
                break;
            case 3:
                $tipoPrompt = 'prensa';               
                break;           
            default:
                $tipoPrompt = ''; 
                break;
        }
        
        $nombrePrompt = null;
        $descripcionPromptUser = null;
        $descripcionPromptSystem = null;
        $endpoint = null;
        $proveedorServicio = null;

        // Verificación del nombre del prompt
        if (isset($_POST['nombre_prompt']) && !empty($_POST['nombre_prompt'])) {
            $nombrePrompt = $_POST['nombre_prompt'];
        } else {
            return json_encode([
                'error' => 1,
                'mensaje' => 'El nombre del prompt debe ir completo'
            ]);
        }

        // Verificación de la descripción del prompt para el rol de usuario
        if (isset($_POST['descripcion_prompt_user']) && !empty($_POST['descripcion_prompt_user'])) {
            $descripcionPromptUser = $_POST['descripcion_prompt_user'];
        } else {
            return json_encode([
                'error' => 1,
                'mensaje' => 'La descripción del prompt rol user debe ir completa.'
            ]);
        }

        // Verificación de la descripción del prompt para el rol del sistema
        if (isset($_POST['descripcion_prompt_system']) && !empty($_POST['descripcion_prompt_system'])) {
            $descripcionPromptSystem = $_POST['descripcion_prompt_system'];
        } else {
            return json_encode([
                'error' => 1,
                'mensaje' => 'La descripción del prompt rol system debe ir completa.'
            ]);
        }

        // Verificación del endpoint
        if (isset($_POST['end_point']) && !empty($_POST['end_point'])) {
            $endpoint = $_POST['end_point'];
        }

        // Verificación del proveedor del servicio (No confundir con el proveedor de AI)
        if (isset($_POST['proveedor_servicio']) && !empty($_POST['proveedor_servicio'])) {
            $proveedorServicio = $_POST['proveedor_servicio'];
        }
        
        // Manejo de ratios
        $cuentasRatios = $_POST['cuentas_ratios'] ?? null;
        $patrimonialRatios = $_POST['patrimonial_ratios'] ?? null;
        $rentabilidadRatios = $_POST['rentabilidad_ratios'] ?? null;
        $financieroRatios = $_POST['financiero_ratios'] ?? null;
        $eficienciaRatios = $_POST['eficiencia_ratios'] ?? null;

        $todosRatios = [];
        if (!empty($cuentasRatios)) {
            $todosRatios = array_merge($todosRatios, $cuentasRatios);
        }
        if (!empty($patrimonialRatios)) {
            $todosRatios = array_merge($todosRatios, $patrimonialRatios);
        }
        if (!empty($rentabilidadRatios)) {
            $todosRatios = array_merge($todosRatios, $rentabilidadRatios);
        }
        if (!empty($financieroRatios)) {
            $todosRatios = array_merge($todosRatios, $financieroRatios);
        }
        if (!empty($eficienciaRatios)) {
            $todosRatios = array_merge($todosRatios, $eficienciaRatios);
        }

        // Convertir todos los ratios a una cadena separada por comas
        $todosRatios = !empty($todosRatios) ? implode(',', $todosRatios) : null;

        // Verificación de la acción
        $accion = isset($_POST['accion']) && !empty($_POST['accion']) ? $_POST['accion'] : null;

        // Verificación del ID del prompt
        $idPrompt = isset($_POST['id_prompt']) && !empty($_POST['id_prompt']) ? $_POST['id_prompt'] : null;

        $datos = SQLConnection::backendStoreProcedure(
            'gestor_prompts', 
            array('seleccionar', null, null, null, null, null, null, null, null)
        );        
               
        foreach ($datos as $dato) {
            if ($accion == 'insertar' && $dato->prompt_name == $nombrePrompt) {
                return json_encode([
                    'error' => 3,
                    'mensaje' => 'El nombre del Prompt ya existe, elija uno diferente.'
                ]);
            } elseif ($accion == 'modificar' && $nombrePrompt == $dato->prompt_name && $idPrompt != $dato->id_prompt) {
                return json_encode([
                    'error' => 3,
                    'mensaje' => 'El nombre del Prompt ya existe, elija uno diferente.'
                ]);
            } elseif ($accion != 'insertar' && $accion != 'modificar') {
                return 'ERROR_ACCION_REGISTRO';
            }
        }    
               

        $datos = [
            $accion,
            $nombrePrompt, 
            $descripcionPromptUser,
            $descripcionPromptSystem,
            $endpoint,
            $proveedorServicio,
            Session::get('usuario')->user_id,
            1,
            $idPrompt,             
            $todosRatios,
            $tipoPrompt,
            null,
            $pais,
            $tipoCarga,            
            $claes            
        ];
        
        $resultado = SQLConnection::backendStoreProcedure('gestor_prompts', $datos);

        $tabla = self::tablaPromptsv2($estadoPrompts,$tablaTipoPrompt);                            

        return json_encode([
            'error' => 0,
            'mensaje' => 'Prompt exitosamente creado.',
            'tabla' => $tabla
        ]);
    }

    public static function duplicarRegistroPrompt()
    {
        $id_prompt = Request::input('id_prompt');
        $prompt_data = SQLConnection::backendStoreProcedure('gestor_prompts', array('SELECT_ONE', null, null, null, null, null, null, null, $id_prompt));
        
        $prompt_data = $prompt_data[0];
        
        $accion = 'insertar';
        $nombrePrompt = 'Copia de ' . $prompt_data->prompt_name;
        $descripcionPromptUser = $prompt_data->user_prompt;
        $descripcionPromptSystem = $prompt_data->system_prompt;
        $endpoint = $prompt_data->ai_endpoint;
        $proveedorServicio = $prompt_data->ai_provider;
        $idPrompt = NULL;        
        $todosRatios = $prompt_data->lista_ind_balance;
        $tipoPrompt = $prompt_data->type_prompt;        

        $datos = [
            $accion,
            $nombrePrompt, 
            $descripcionPromptUser,
            $descripcionPromptSystem,
            $endpoint,
            $proveedorServicio,
            Session::get('usuario')->user_id,
            1,
            $idPrompt,             
            $todosRatios,
            $tipoPrompt,
            NULL
        ];

        $resultado = SQLConnection::backendStoreProcedure('gestor_prompts', $datos);
        
        return 0;
    }

    /**
    * Cambia el estado de un prompt especifico
    *    
    * @return string Un JSON que indica si la funcion se ejecuto correctamente
    */
    public static function modalPromptModificarestado() 
    {        
        // Cambia el estado del prompt
        SQLConnection::backendStoreProcedure(
            'gestor_prompts', 
            array('activo', null, null, null, null, null, null, $_POST['estado'], $_POST['id_prompt'])
        );

        return json_encode(
            array(
                "error" => 0, 
                "mensaje" => "Se ha cambiado exitosamente el estado del prompt."
            )
        );
    }
   
    /**
    * Muestra una tabla de prompts basada en el estado
    *
    * Esta funcion recibe el estado, generar y retornar la tabla de prompts 
    * Si no se proporciona un estado valido, retorna un mensaje de error
    *
    * @return string La tabla de prompts generada o un mensaje de error si el estado no es valido
    */
    public function mostarTablaPrompts() 
    {
        // Obtengo el estado
        $estado = Request::input('estado');

        // Verifica si el estado no es nulo
        if ($estado != NULL) {
            // Genera y retorna la tabla de prompts basada en el estado proporcionado
            $tabla = self::tablaPrompts($estado);
            return $tabla;
        } else {
            // Retorna un mensaje de error si el estado es invalido o no fue recibido
            return 'El cuit es inválido o no fue recibido';
        }
    }

    /**
    * Filtra los prompts por estado de activo y genera una tabla
    *
    * Esta funcion obtiene los datos de prompts y los filtra segun el estado. Despues, genera una vista de tabla con los datos filtrados
    *
    * @param string $estado El estado de los prompts a filtrar
    * @return string La vista de la tabla generada con los datos filtrados de los prompts o un mensaje de error
    */
    public static function tablaPrompts($estado)
    {
        $datos_prompt = [];

        // Verifica si el estado no es nulo
        if ($estado != NULL) {
            try {
                // Obtiene los datos de los prompts
                $datos = SQLConnection::backendStoreProcedure(
                    'gestor_prompts', 
                    array('seleccionar', null, null, null, null, null, null, null, null)
                );

                // Verifica que los datos no esten vacios
                if (!empty($datos)) {
                    // Si el estado es "todos", incluye todos los datos
                    if ($estado == "todos") {
                        $datos_prompt = $datos;
                    } else {
                        // Filtra los datos segun el estado 
                        foreach ($datos as $key => $dato) {
                            if ($dato->active == $estado) {
                                array_push($datos_prompt, $dato);
                            }
                        }
                    }
                }
            } catch (\Throwable $th) {
                // Retorna un mensaje de error en caso de excepcion
                return 'ERROR_DATOS_TABLA';
            }
        }

        // Genera la vista de la tabla con los datos filtrados
        $tabla = \View::make('/seccion-prompts/tabla_prompt')->with(compact('datos_prompt'))->render();

        return $tabla;
    }   
    
    /**
    *
    * Esta funcion obtiene los datos de un prompt usando su ID, y tambien una lista de ratios financieros 
    *
    * @return array Los datos del prompt y una lista de ratios financieros
    */
    function modificarPrompt()
    {           
        // ID del prompt 
        $id_prompt = Request::input('id_prompt');

        // Obtiene los datos del prompt 
        $prompt_data = SQLConnection::backendStoreProcedure(
            'gestor_prompts', 
            array('SELECT_ONE', null, null, null, null, null, null, null, $id_prompt)
        );

       /*  $userPrompt = $prompt_data[0]->user_prompt;
        $systemPrompt = $prompt_data[0]->system_prompt;
    
        $variablesSystem = self::contarPalabrasEntreDelimitadores($systemPrompt);
        $cantVariablesSystem = self::contarTotalPalabrasEntreDelimitadores($systemPrompt);

        $variablesUser = self::contarPalabrasEntreDelimitadores($userPrompt);
        $cantVariablesUser = self::contarTotalPalabrasEntreDelimitadores($userPrompt);

        $prompt_data[0]->variables_system[] = $variablesSystem;
        $prompt_data[0]->cant_variables_system[] = $cantVariablesSystem;
        $prompt_data[0]->variables_user[] = $variablesUser;
        $prompt_data[0]->cant_variables_user[] = $cantVariablesUser; */
        
        // Divide la lista de ratios en un array
        $lista_ratios = explode(',', $prompt_data[0]->lista_ind_balance);

        // Obtiene los nombres de los ratios 
        $ratios_nombres = SQLConnection::backendStoreProcedure('abm_nombre_ratios', array('SELECT_ALL'));

        /*
            # Filtra los nombres de los ratios según la lista de ratios obtenida
            $ratios_nombre = array_filter($ratios_nombres, function($obj) use ($lista_ratios) {
                return in_array($obj->nombre_campo, $lista_ratios);
            });                        
            $ratios_nombres = array_values($ratios_nombre);
        */

        return $prompt_data;
    }

    /**
    * Obtiene la lista de modelos disponibles desde la API de OpenAI
    *
    * Esta funcion hace una solicitud a la API de OpenAI para obtener la lista de modelos disponibles 
    *
    * @return array La lista de modelos disponibles desde la API de OpenAI
    */
    public static function obtenerModelosGpt()
    {
        // URL de la API de OpenAI para obtener modelos
        $url = 'https://api.openai.com/v1/models';

        $apiKey = env("apiKey_chatgpt");

        // Inicializa una session cURL
        $ch = curl_init($url);

        // Configura las opciones de cURL
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $apiKey
        ]);

        // Ejecuta la solicitud cURL y obtiene la respuesta
        $response = curl_exec($ch);

        // Cierra la session cURL
        curl_close($ch);

        $models = json_decode($response, true);

        return $models['data'];
    }

    //Nueva vista de prompts
    public static function panelPrompts(){
        //TODO: VISTA NO EXISTE
        return view('/seccion-prompts/panel_prompts');
    }

    public static function tipoPrompt()
    {
        $tipoPrompt = Request::input('tipoPrompt');
        $estadoPrompt = Request::input('estadoPrompt');

        switch ($tipoPrompt) {
            case 1:
                $tipoPrompt = 'edicto';
                break;
            case 2:
                $tipoPrompt = 'balance';
                break;
            case 3:
                $tipoPrompt = 'prensa';
                break;
            case 'default':
                $tipoPrompt = 'todo';
                break;
            default:
                $tipoPrompt = 'vacio'; 
                break;
        }
        
        $promptsFiltrados = [];
        if (in_array($tipoPrompt, ['todo', 'vacio'])) {
            /* $promptsFiltrados = SQLConnection::backendStoreProcedure(
                'gestor_prompts', 
                ['seleccionar', null, null, null, null, null, null, null, null]
            ); */            
            $promptsFiltrados = SQLConnection::backendStoreProcedure(
                'gestor_prompts', 
                array('seleccionar', null, null, null, null, null, null, null, null)
            );
        } else {
            $promptsFiltrados = SQLConnection::backendStoreProcedure(
                'gestor_prompts', 
                ['PROMPTS_TYPE', null, null, null, null, null, null, null, null, null, $tipoPrompt]
            );
        }

        // Filtrar por estado ('1', '0', o 'todos') 
        if ($estadoPrompt !== 'todos') {
            $promptsFiltrados = array_filter($promptsFiltrados, fn($prompt) => $prompt->active == $estadoPrompt);
        }
        
        return json_encode($promptsFiltrados);
    }
    
    public static function filtrarEstadoTablaPrompts()
    {
        $tipoPrompt = Request::input('tipoPrompt');
        $estadoPrompt = Request::input('estadoPrompt');
        

       /*  $datos_prompt = SQLConnection::backendStoreProcedure(
            'gestor_prompts', 
            ['seleccionar', null, null, null, null, null, null, null, null]
        ); */
        $datos_prompt = SQLConnection::backendStoreProcedure(
            'gestor_prompts', 
            array('seleccionar', null, null, null, null, null, null, null, null)
        );

        // Filtro por tipo de prompt
        $tiposPrompt = [
            'default' => null,
            '2' => 'balance',
            '1' => 'edicto',
            '3' => 'prensa'
        ];

        // Si no es 'default', filtramos por tipo de prompt        
        if (isset($tiposPrompt[$tipoPrompt]) && $tipoPrompt !== 'default') {            
            $datos_prompt = array_filter($datos_prompt, function($prompt) use ($tipoPrompt, $tiposPrompt) {
                return isset($prompt->type_prompt) && $prompt->type_prompt == $tiposPrompt[$tipoPrompt];
            });
        }        

        // Filtrar por estado ('1', '0', o 'todos') 
        if ($estadoPrompt !== 'todos') {
            $datos_prompt = array_filter($datos_prompt, fn($prompt) => $prompt->active == $estadoPrompt);
        }

        return json_encode($datos_prompt);
    }

    public static function contarPalabrasEntreDelimitadores($texto) {
        // Expresión regular para capturar texto entre ~~
        preg_match_all('/~(.*?)~/', $texto, $matches);
        
        $resultados = [];
        
        // Recorremos los matches y contamos las palabras
        foreach ($matches[1] as $match) {
            $palabras = str_word_count($match); // Contar palabras
            $resultados[] = [
                'texto' => $match,
            ];
        }
        
        return $resultados;
    }

    public static function contarTotalPalabrasEntreDelimitadores($texto) {
        // Expresión regular para tomar el texto entre ~~
        preg_match_all('/~(.*?)~/', $texto, $matches);
        
        $totalPalabras = 0;
    
        // Recorremos los matches y contamos las palabras
        foreach ($matches[1] as $match) {
            $palabras = preg_split('/\s+/', trim($match)); 
            $totalPalabras += count($palabras);
        }
        
        return $totalPalabras;
    }

    public static function altaProvedorAi(){
        /* SQLConnection::backendStoreProcedure(
            'gestor_ai_provider', 
            ['INSERT_PROVIDER', NULL, 'Open AI', 'https://api.openai.com/v1/chat/completions', '12345', Session::get('usuario')->user_id, 1]
        ); */

        $test = SQLConnection::backendStoreProcedure(
            'gestor_ai_provider', 
            ['ALL_PROVIDERS']
        );
        
        /* 
            @accion VARCHAR(20),
            @ai_provider int = NULL,    
            @prov_name VARCHAR(255) = NULL, 
            @endpoint_url VARCHAR(100) = NULL,
            @apikey VARCHAR(100) = NULL,
            @user_id VARCHAR(100) = NULL,
            @active bit = NULL 
        */

        dd($test);
    }

    /**
     * Funcion que va a dar de alta un registro de ratios
     */
    public static function altaRatioNombre(){
        //SQLConnection::backendStoreProcedure('abm_nombre_ratios', ['INSERT', 'Ajuste de Capital', 'ajucap', 'CUENTAS']);
        dd('exito');
    }


    /**
     * Esta funcion va a mostrar los modelos que existen para cierto proveedor
     * Si elegimos de provedor a Open Ai nos va a devolver los modelos que este maneje
     * Nota : Se podria tambien traer modelos que coincidan con el tipo de prompt que se va a realizar
     */
    public static function mostrarModelosProveedor(){
        dd($_POST);
    }

    public static function tablaPromptsv2($estado, $tipoPrompt){
        
        // Obtiene los datos de los prompts
        $datos = SQLConnection::backendStoreProcedure('gestor_prompts', array('seleccionar', null, null, null, null, null, null, null, null, null, null));

        switch ($tipoPrompt) {
            case 1:
                $tipoPrompt = 'edicto';
                break;
            case 2:
                $tipoPrompt = 'balance';
                break;
            case 3:
                $tipoPrompt = 'prensa';
                break;
            case 'default':
                $tipoPrompt = 'todo';
                break;
        }
        
        $promptsFiltrados = [];
        if ($tipoPrompt == 'todo') {            
            $promptsFiltrados = SQLConnection::backendStoreProcedure(
                'gestor_prompts', 
                ['seleccionar', null, null, null, null, null, null, null, null, null, null]
            );
        } else {            
            $promptsFiltrados = SQLConnection::backendStoreProcedure(
                'gestor_prompts', 
                ['PROMPTS_TYPE', null, null, null, null, null, null, null, null, null, $tipoPrompt]
            );
        }

        
       /*  if ($estado !== '0') {
            $promptsFiltrados = array_filter($promptsFiltrados, function ($prompt) use ($estado) {
                return isset($prompt->active) && $prompt->active === $estado;
            });
        } */
        
        // Filtro por tipo de prompt
        $tiposPrompt = [
            'todo' => null,
            '2' => 'balance',
            '1' => 'edicto',
            '3' => 'prensa'
        ];

        // Si no es 'default', filtramos por tipo de prompt
        if (isset($tiposPrompt[$tipoPrompt]) && $tipoPrompt !== 'todo') {
            $promptsFiltrados = array_filter($promptsFiltrados, function($prompt) use ($tipoPrompt, $tiposPrompt) {
                return isset($prompt->type_prompt) && $prompt->type_prompt === $tiposPrompt[$tipoPrompt];
            });
        }
        
        // Filtrar por estado ('1', '0', o 'todos')
        if ($estado !== 'todos') {
            $promptsFiltrados = array_filter($promptsFiltrados, function($prompt) use ($estado) {
                return isset($prompt->active) && $prompt->active == $estado;
            });
        }

        return $promptsFiltrados;
    }

}