<?php
namespace App\Http\Controllers;

use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Request;
use Carbon\Carbon;
use App\Http\Controllers\IAController;
use App\Custom\SQLConnection;
use App\Custom\Misc;
use DateTime;
use stdClass;
use DB;
use Log;
use Storage;

class ApiDashboardController extends Controller {
    

    // --- Método para la carga inicial de la vista ---
    public static function indexDashboardApi_Json()
    {   
        // Definir filtros por defecto para la carga inicial: MES ACTUAL
        $defaultFilters = [
            'periodo' => 'mensual',   // <--- CAMBIADO a 'mensual'
            'mes' => date('n'),     // <--- Correcto: Mes actual (1-12)
            'dia' => null,          // <--- CAMBIADO a null (no aplica para mensual)
            'producto' => null,     // 'todos'
            'cliente' => null,      // 'todos'
        ];

        $initialData = self::getDashboardDataFromFile($defaultFilters); // Usará la instancia actual si no es estático
        Carbon::setLocale('es');

        if (!$initialData) {
             Log::warning("No se pudieron obtener datos iniciales del archivo para el dashboard API (Mes Actual).");
             $currentMonthName = Carbon::now()->monthName; // Nombre del mes actual
             $initialData = [
                'metadata' => [
                    'mesConsultado' => "Datos no disp. ($currentMonthName)", // Indica el mes intentado
                    'subtitulo' => 'Mes Actual',
                    'periodo' => $defaultFilters['periodo']
                ],
                'cards' => [],
                'graphs' => [],
             ];
             // Poblar con claves de gráficos vacías...
              $expectedGraphs = ['solicitudesPeriodo', 'tasaAciertosErroresPie', /* ... */ 'distribucionTiempos'];
              foreach ($expectedGraphs as $graphKey) {
                  $initialData['graphs'][$graphKey] = ['categories' => [], 'series' => []];
                   if ($graphKey === 'tasaAciertosErroresPie') { $initialData['graphs'][$graphKey] = ['seriesData' => []]; }
              }
        }

        $clientesApis = SQLConnection::backendStoreProcedure('getClientesDashboardApi',[]);
        $productosApis = SQLConnection::backendStoreProcedure('getProductosDashboardApi',[]); 


        usort($clientesApis, function ($a, $b) {
            return strcasecmp($a->nombre_cliente, $b->nombre_cliente);
        });

        usort($productosApis, function ($a, $b) {
            return strcasecmp($a->nombre_producto, $b->nombre_producto);
        });

        $ultimaConsultaProvedores = SQLConnection::backendStoreProcedure('fechas_consultas_API',[]); 

        $ultimaConsultaProvedoresArg = [];

        foreach ($ultimaConsultaProvedores as $consulta) {
            $ultimaConsultaProvedoresArg[] = json_decode(json_encode([
                'computed' => $consulta->proveedor,
                'computed1' => Carbon::parse($consulta->fecha)->format('d/m/Y H:i:s'),
            ]));
        }

        return view('dashboard-api/dashboard_new')->with(compact([
            'initialData','clientesApis','productosApis','ultimaConsultaProvedoresArg'
        ]));
    }

    

    public static function getDashboardDataFromFile(array $filters)
    {
        $productoId = $filters['producto'] ?? null;
        $clienteId = $filters['cliente'] ?? null;
    
        // Determinar el rango de fecha
        if ($filters['periodo'] === 'diario' && !empty($filters['dia'])) {
            $rangoFecha = $filters['dia']; // Formato esperado: YYYY-MM-DD
        } elseif ($filters['periodo'] === 'mensual' && !empty($filters['mes'])) {
            $año = $filters['anio'] ?? date('Y');
            $rangoFecha = $año . '-' . str_pad($filters['mes'], 2, '0', STR_PAD_LEFT); // YYYY-MM
        } else {
            Log::warning("Período o fecha no especificados claramente para buscar archivo.", $filters);
            return null;
        }
    
        try {
            $baseDir = env('API_DASHBOARD_JSON_DIR');
    
            // Uso mismas funciones que use en DashboardJSONController (desde Misc)
            $rutaCarpeta = Misc::generarRutaCarpeta($rangoFecha, $clienteId, $productoId, $baseDir);
            $filename = Misc::generarNombreArchivo($productoId, $clienteId, $rangoFecha);
            $filePath = "{$rutaCarpeta}/{$filename}.json";
            //dd($filePath);
            $datos = null;
            if (file_exists($filePath)) {
            $file_get = file_get_contents($filePath);
            if ($file_get !== false) {
                $datos = json_decode($file_get, true);
            } else {
                Log::error("No se pudo leer el archivo JSON: " . $filePath);
            }
        } else {
            Log::warning("Archivo JSON no encontrado: " . $filePath);
        }
        return $datos;

        } catch(\Exception $e) {
            Log::error("Error al procesar archivo JSON: " . $e->getMessage(), $filters);
            return null;
        }
    }


    public static function getDashboardDataFromFileOrg(array $filters)
    {
        $productoPart = !empty($filters['producto']) ? $filters['producto'] : 'todos';
        $clientePart = !empty($filters['cliente']) ? $filters['cliente'] : 'todos';
        $fechaPart = '';

        try {
             if ($filters['periodo'] === 'diario' && !empty($filters['dia'])) {
                 $targetDate = Carbon::createFromFormat('Y-m-d', $filters['dia']);
                 $fechaPart = $targetDate->format('Y_m_d'); // FORMATO: Año_MesConCero_DiaconCero
             } elseif ($filters['periodo'] === 'mensual' && !empty($filters['mes'])) {
                 $year = date('Y'); // Año actual
                 // ASUNCIÓN: El archivo mensual es solo el mes
                 $targetDate = Carbon::createFromDate($year, $filters['mes']);
                 $fechaPart = $targetDate->format('Y_m'); // FORMATO: Año_MesConCero_DiaconCero
             } else {
                 // Fallback si el período no es claro o faltan datos
                 Log::warning("Período o fecha no especificados claramente para buscar archivo.", $filters);
                 $targetDate = Carbon::today(); // O el último día disponible?
                 $fechaPart = $targetDate->format('Y_m_d');
                 // Considera si deberías devolver null aquí directamente si los filtros no son válidos
                 // return null;
             }
        } catch (\Exception $e) {
            Log::error("Error al procesar fecha para nombre de archivo: " . $e->getMessage(), $filters);
            return null; // No se puede determinar el archivo
        }

        if (empty($fechaPart)) {
             Log::error("No se pudo determinar la parte de fecha para el nombre de archivo.", $filters);
             return null;
        }

        $filename = "producto-{$productoPart}_cliente-{$clientePart}_fecha-{$fechaPart}.json";
        $filePath = env("API_DASHBOARD_JSON_DIR")."/{$filename}";
        // dd($filePath);
        ///home/fidelitas/DevNew/compartido/apiDashboardJson/producto-todos_cliente-todos_fecha-2025_01_1.json
        $file_exists = file_exists($filePath);
        $datos = null;
        if (file_exists($filePath)) {
            $file_get = file_get_contents($filePath);
            if ($file_get !== false) {
                $datos = json_decode($file_get, true);
            } else {
                // Opcional: loguear error si no pudo leer el archivo
                Log::error("No se pudo leer el archivo JSON: " . $filePath);
            }
        } else {
            // Opcional: loguear archivo no encontrado
            Log::warning("Archivo JSON no encontrado: " . $filePath);
        }
        //var_dump($filePath);
        return $datos;
    }

     // --- filtrarDashboardApi (método AJAX) ---
     // No necesita cambios directos aquí, ya que recibe los filtros del JS
     // y llama a getDashboardDataFromFile que ya tiene la lógica correcta.
    public function filtrarDashboardApi(Request $request)
    {
        $filters = [
            'periodo' => request::input('periodo', 'mensual'),
            'anio' => request::input('anio'),
            'mes' => request::input('mes'),
            'dia' => request::input('dia'),
            'producto' => request::input('producto'),
            'cliente' => request::input('cliente'),
        ];
        //dd($filters);
        $filteredData = self::getDashboardDataFromFile($filters);
        //dd($filteredData);
        if (!$filteredData) {
            Log::warning("No se encontraron datos de archivo para filtros AJAX:", $filters);
    
            $periodo = $filters['periodo'] ?? 'mensual';
            $subtitulo = ($periodo === 'diario') ? "Día seleccionado" : "Mes seleccionado";
    
            // Estructura vacía para respuesta coherente
            $emptyData = [
                'metadata' => [
                    'mesConsultado' => "Sin datos disponibles",
                    'subtitulo' => $subtitulo,
                    'periodo' => $periodo,
                ],
                'cards' => [],
                'graphs' => [],
            ];
    
            $expectedGraphs = [
                'solicitudesPeriodo',
                'tasaAciertosErroresPie',
                'codigosRespuesta',
                'tiempoPromedioProcesamiento',
                'erroresPorCodigo',
                'erroresPorCliente',
                'erroresPorProducto',
                'clientesConMayorUso',
                'productosConMayorUso',
                'tasaAciertosErroresBarra',
                'distribucionTiempos'
            ];
    
            foreach ($expectedGraphs as $graphKey) {
                if ($graphKey === 'tasaAciertosErroresPie') {
                    $emptyData['graphs'][$graphKey] = ['seriesData' => []];
                } else {
                    $emptyData['graphs'][$graphKey] = ['categories' => [], 'series' => []];
                }
            }
    
            return response()->json($emptyData, 200);
        }
        //  sleep(3); 
        return response()->json($filteredData);
    }
     

     public static function ActualDashboardApi(){
             // dd('llego');

            
            $productoId = request::input('producto');
            $clienteId = request::input('cliente');


            $paramsParaSpDirectos = [$productoId, $clienteId];
            
            // Para los SPs envueltos por BackendDashboardApi, la acción va primero en el array de SQLConnection
            $paramsPayloadParaBackendApi = [$productoId, $clienteId];
           // dd($paramsPayloadParaBackendApi);
    
            //dd($paramsPayloadParaBackendApi);
            // ----- LLAMADAS A STORE PROCEDURES -----
    
            $rawSolicitudesTotales = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_TOTAL_CONSULTAS'], $paramsParaSpDirectos));
            $solicitudesTotales = $rawSolicitudesTotales[0] ?? null;
    
            $rawTiempoPromedioResp = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_TIEMPO_PROMEDIO'], $paramsPayloadParaBackendApi));
            $tiempoPromedioResp = $rawTiempoPromedioResp[0] ?? null;
            
            $rawTiempoMayorMenor = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_TIEMPO_MAYOR_MENOR'], $paramsPayloadParaBackendApi));
            $tiempoMayorMenor = $rawTiempoMayorMenor[0] ?? null;
    
            $rawPromedioConsumoApi = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_PROMEDIO_CONSUM_PROD'], $paramsPayloadParaBackendApi));
            $promedioConsumoApi = $rawPromedioConsumoApi[0] ?? null;
                        
            $rawPromedioConsumoCliente = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_PROMEDIO_CONSUM_CLIENT'], $paramsPayloadParaBackendApi));
            $promedioConsumoCliente = $rawPromedioConsumoCliente[0] ?? null;
    
            $totalConsultasClienteGraf = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_CONSULTAS_CLIENTE_GRAF'], $paramsPayloadParaBackendApi));
        
            $totalConsultasProductGraf = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_CONSULTAS_PRODUCT_GRAF'], $paramsPayloadParaBackendApi));
            
            $dataCodigoRespuesta = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_CODIGO_RESP_DATA'], $paramsPayloadParaBackendApi));
        
            $tiempoPromedioProduct = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_TIEMPO_PRODUCT'], $paramsPayloadParaBackendApi));
        
            $rangoTiempos = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_RANGO_TIEMPO'], $paramsPayloadParaBackendApi));
        
            $apisMasErrores = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_APIS_MAS_ERRORES'], $paramsPayloadParaBackendApi));
        
            $totalPromedioRespuestaGraf = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_TOTAL_CONSULTAS_GRAF'], $paramsPayloadParaBackendApi));

            // $codResultAnual = SQLConnection::backendStoreProcedure('api_TasaErrores', $paramsParaSpDirectos);
            $codResultAnual = SQLConnection::backendStoreProcedure('backendDashboardApiActual', ['GET_COD_RESULTADOS_AN']);
            
            $tiempoPromedioAn = SQLConnection::backendStoreProcedure('backendDashboardApiActual', array_merge(['GET_TIEMPO_PROM_AN']), $paramsParaSpDirectos);

            //Tiempo procesamiento para actual
            $periodo = 'actual';
            $tiempoProce = SQLConnection::backendStoreProcedure('api_promedioTiempoProcesamiento', [$periodo, null, $productoId, $clienteId]);
            $tiemposDetallados = [];

            //Paso $tiempoProce de array a colección, esto hace que sea mas facil agregar contenidos al json en caso de cambiar SP
            foreach ($tiempoProce as $item) {
                // Normalizamos el nombre del proveedor como clave para que coincida con clases de la blade
                $key = strtolower(str_replace(' ', '_', $item->proveedor ?? 'global'));

                // Armamos el array base
                $tiemposDetallados[$key] = [
                    'duracion' => $item->duracion !== null ? (float) $item->duracion : null,
                ];

                // Se pasa nombres solo a primera key porque es la unica que los tendria
                if ($key === 'promedio_total_apis') {
                    $tiemposDetallados[$key]['nombre_cliente'] = $item->nombre_cliente ?? null;
                    $tiemposDetallados[$key]['nombre_producto'] = $item->nombre_producto ?? null;
                } else {
                    $tiemposDetallados[$key]['proveedor'] = $item->proveedor;
                }
            }
 
 
             // ----- PROCESAMIENTO DE DATOS PARA GRÁFICOS (Adaptado de tu código) -----
             
             // GRAFICO: Consumo por Cliente
             $nombre_cliente_graf = [];
             $consumo_total_graf = [];
             if(!empty($totalConsultasClienteGraf)){
                 foreach ($totalConsultasClienteGraf as $dato) {
                     $nombre_cliente_graf[] = $dato->nombre_cliente ?? 'N/A';
                     $consumo_total_graf[]= (float)($dato->consumo_total ?? 0);
                 }
             }
 
         // GRAFICO: Consumo por Producto/API
             $producto_graf = [];
             $total_registros_graf = [];
             if (!empty($totalConsultasProductGraf)) {
                 foreach ($totalConsultasProductGraf as $dato) {
                     $producto_graf[] = $dato->nombre_producto ?? 'N/A';
                     $total_registros_graf[]= (float)($dato->total_registros ?? 0);
                 }
             }
 
         // GRAFICO: Códigos de Respuesta
             $codigo_resultado_graf = [];
             $cantidad_Respuesta_graf = [];
             if (!empty($dataCodigoRespuesta)) {
                 foreach ($dataCodigoRespuesta as $dato) {
                     $codigo_resultado_graf[] = (string)($dato->codigo ?? 'N/A');
                     $cantidad_Respuesta_graf[]= (float)($dato->cantidad ?? 0);
                 }
             }
             
         // GRAFICO: APIs más Lentas
             $tiempo_api_resp_graf = [];
             $nombre_api_graf = [];
             if(!empty($tiempoPromedioProduct)){
                 foreach ($tiempoPromedioProduct as $dato) {
                     $tiempo_api_resp_graf[] = (float)($dato->promedio_duracion ?? 0.0);
                     $nombre_api_graf[]= $dato->nombre_producto ?? 'N/A';
                 }
             }
             
         // GRAFICO: Distribución de Tiempos
             $rango_tiempo_graf = [];
             $cantidad_Tiempo_graf = [];
             if(!empty($rangoTiempos)){
                 foreach ($rangoTiempos as $dato) {
                     $rango_tiempo_graf[] = $dato->rango_tiempo ?? 'N/A';
                     $cantidad_Tiempo_graf[]= (float)($dato->cantidad ?? 0);
                 }
             }
             
         // GRAFICO: APIs con más Errores
             $nombre_producto_errores_graf = [];
             $series_errores_graf = [];
             $tipos_error_keys = [ // Definir los tipos de error y las propiedades correspondientes del objeto $dato
                 '307' => 'error_307', '306' => 'error_306', 'Internal Error' => 'internal_error',
                 'Internal E' => 'internal_e', 'Error General' => 'error_general',
                 'Error Producto' => 'error_producto', '400' => 'error_400',
                 'falló RENAPER' => 'fallo_renaper', 'fallo genérico' => 'fallo_generico', 'falló sistema' => 'fallo_sistema','timeout excedido' => 'timeout_max'
             ];
             $errores_por_tipo_tmp = [];
             
             if(!empty($apisMasErrores)){
                 foreach (array_keys($tipos_error_keys) as $key) {
                     $errores_por_tipo_tmp[$key] = []; // Inicializa un array para cada tipo de error
                 }
                 foreach ($apisMasErrores as $dato) {
                     $nombre_producto_errores_graf[] = $dato->nombre_producto ?? 'N/A';
                     foreach ($tipos_error_keys as $displayName => $property) {
                     $errores_por_tipo_tmp[$displayName][] = (int)($dato->{$property} ?? 0);
                     }
                 }
                 foreach($errores_por_tipo_tmp as $name => $data_errores) { // Renombré $data a $data_errores
                     if (!empty($data_errores)) { // Solo añadir series si tienen datos
                         $series_errores_graf[] = ['name' => $name, 'data' => $data_errores];
                     }
                 }
             }
             // Asegurarse que $nombre_producto_errores_graf tenga la misma longitud que los 'data' en $series_errores_graf
             // Si $apisMasErrores estaba vacío, $nombre_producto_errores_graf también lo estará, lo cual es correcto.
             
             // GRAFICO: Solicitudes OK/Error en el Periodo
             $categorias_periodo_graf = [];
             $aciertos_periodo_graf = [];
             $errores_periodo_graf = [];
        //dd($tiempoPromedioAn);
         if(!empty($totalPromedioRespuestaGraf)){
                 foreach ($totalPromedioRespuestaGraf as $dato) {
                     // Asumiendo que $dato->mes es YYYY-MM para mensual
                     $categorias_periodo_graf[] = Carbon::createFromFormat('Y-m', $dato->mes)->translatedFormat('M');
                     $aciertos_periodo_graf[] = (int)($dato->total_ok ?? 0);
                     $errores_periodo_graf[] = (int)($dato->total_error ?? 0) ;
                 }
             }
         //GRAFICO: TIEMPO DE PROCESAMIENTO
             $mes_tiempoPromedio_categorias = [];
             $promedio_duracion_data = [];
             if(!empty($tiempoPromedioAn)){
                 foreach ($tiempoPromedioAn as $dato){
                     $mes_tiempoPromedio_categorias[] =(int)($dato->hora ?? 0);
                     $promedio_duracion_data[] = (float)($dato->promedio_duracion ?? 0.0);
                 }
 
             }
             // GRAFICO: Tasa de Errores por Código en el Periodo
             // $campoFecha es la columna en $codResultAnual que tiene la fecha ('dia' o 'mes')
             $campoFechaUsar = 'hora'; // La columna que contiene la hora (0, 8, etc.)
             $agrupado_tasa_errores_graf = [];
             $series_tasa_errores_graf = [];
     
             if (!empty($codResultAnual)) {
                 // 1. Obtener todas las horas únicas y formatearlas para las categorías del gráfico
                 $agrupado_tasa_errores_graf = collect($codResultAnual)
                     ->pluck($campoFechaUsar) // Obtiene todas las 'hora'
                     ->map(function ($hora) {
                         // Formatear la hora como "HH:00"
                         return str_pad((string)$hora, 2, '0', STR_PAD_LEFT) . ':00';
                     })
                     ->unique()
                     ->sort() // Ordenar las horas cronológicamente
                     ->values()
                     ->all();
                     
                 // 2. Obtener todos los códigos de resultado únicos
                 $codigos = collect($codResultAnual)
                     ->pluck('codigo_resultado')
                     ->unique()
                     ->filter() // filter() para quitar nulos/vacíos
                     ->values()
                     ->all();
     
                 // 3. Inicializar la estructura para almacenar errores por código y por hora formateada
                 $erroresPorHoraYCodigo = [];
                 foreach ($codigos as $codigo) {
                     // Usar las horas formateadas como claves
                     $erroresPorHoraYCodigo[(string)$codigo] = array_fill_keys($agrupado_tasa_errores_graf, 0);
                 }
                 
                 // 4. Llenar la estructura con los totales de error
                 foreach ($codResultAnual as $item) {
                     $horaItem = $item->{$campoFechaUsar}; // Obtener la hora del item (ej. 0, 8)
                     // Formatear la hora del item de la misma manera que las categorías
                     $horaFormateada = str_pad((string)$horaItem, 2, '0', STR_PAD_LEFT) . ':00';
                     
                     $codigo = (string)($item->codigo_resultado ?? 'N/A');
     
                     // Verificar que el código y la hora formateada existan en nuestra estructura
                     if (isset($erroresPorHoraYCodigo[$codigo]) && array_key_exists($horaFormateada, $erroresPorHoraYCodigo[$codigo])) {
                         $erroresPorHoraYCodigo[$codigo][$horaFormateada] += (int)($item->total_error ?? 0);
                     }
                 }
     
                 // 5. Preparar las series para el gráfico
                 foreach ($erroresPorHoraYCodigo as $codigo => $data_errores_por_hora) {
                     $series_tasa_errores_graf[] = [
                         'name' => $codigo, // El nombre de la serie es el código de error
                         'data' => array_values($data_errores_por_hora), // Los valores de error para cada hora
                     ];
                 }
             }
 
             // ----- METADATA -----
        
             $ahora = Carbon::now();
             $horaParaSubtitulo = Carbon::now()->subHour(); // Resta una hora a la hora actual
     
             // Formato para "Datos al DD de MES de YYYY HH:MM"
             $mesConsultadoStr = "Datos al " . $ahora->translatedFormat('j \d\e F \d\e Y H:i'); 
             
             // Subtítulo con la hora anterior
             $subtitulo = 'DATOS DESDE LAS ' . $horaParaSubtitulo->format('H:00') . ' HASTA LAS ' . $ahora->format('H:00');
             // O si prefieres un rango más explícito incluyendo minutos:
             // $subtitulo = 'RANGO DE DATOS: ' . $horaParaSubtitulo->format('H:i') . ' - ' . $ahora->format('H:i');
             // O si simplemente quieres indicar que los datos son de "la última hora hasta ahora":
             // $subtitulo = 'DATOS DE LA ÚLTIMA HORA (DESDE ' . $horaParaSubtitulo->format('H:i') . ')';
     
     
             $metadataPeriodo = 'actual'; // Para la propiedad 'periodo' en metadata
     
             if ($productoId) {
                 $subtitulo .= " - Producto: $productoId";
             }
             if ($clienteId) {
                 $subtitulo .= " - Cliente: $clienteId";
             }
     
             // Si se filtra por producto o cliente, podrías añadirlo al subtitulo
             // if($productoId) $subtitulo .= " - Prod: $productoId";
             // if($clienteId) $subtitulo .= " - Cli: $clienteId";
 
 
             /**esto se va a borrar  */
                 // --- INICIO DE DATOS HARDCODEADOS PARA EL HEATMAP --
                             $datosUptimeHeatmap = [
                                 'monthName' => '',
                                 'daysInMonth' => '',
                                 'services' => [
                                     [
                                         'name' => 'FIDELITAS',
                                         'overallUptime' => '',
                                         'dailyData' => ''
                                     ],
                                     [
                                         'name' => 'RENAPER',
                                         'overallUptime' => '',
                                         'dailyData' => ''
                                     ],
                                     [
                                         'name' => 'ARCA',
                                         'overallUptime' => '',
                                         'dailyData' => ''
                                     ]
                                 ]
                             ];
             // ----- CONSTRUIR EL JSON FINAL -----
             $resultado = [
                 'metadata' => [
                     'mesConsultado' => $mesConsultadoStr, // Este puede seguir siendo la hora exacta de la consulta
                    'subtitulo' => $mesConsultadoStr,           // Este es el que modificamos
                    'periodo' => $metadataPeriodo,
                 ],
                 'cards' => [
                    'solicitudes' => [
                        'total' => (int)($solicitudesTotales->cantidad_total ?? 0),
                        'ok' => (int)($solicitudesTotales->total_ok ?? 0),
                        'error' => (int)($solicitudesTotales->total_error ?? 0),
                    ],
                    'Ultrenaper' => '',
                    'Ultarca' => '',
                    'tiempoPromedioSegundos' => (float)($tiempoPromedioResp->segundos ?? 0.0), // Asumiendo que la propiedad es 'segundos'
                    'tiemposExtremos' => [
                    'min' => isset($tiempoMayorMenor->duracion_minima) ? (float)$tiempoMayorMenor->duracion_minima : null,
                    'max' => isset($tiempoMayorMenor->duracion_maxima) ? (float)$tiempoMayorMenor->duracion_maxima : null,
                    ],
                    'consumoPromedio' => [
                        'porApi' => (float)($promedioConsumoApi->promedio_por_api ?? 0.0),
                        'porCliente' => (float)($promedioConsumoCliente->promedio_por_cliente ?? 0.0),
                    ],
                    'tiemposDetallados' => $tiempoProce ? $tiemposDetallados : null,
                ],
             'graphs' => [
                     'solicitudesPeriodo' => [
                     'categories' => $categorias_periodo_graf,
                     'series' => [
                         [ 'name' => 'Aciertos', 'data' => $aciertos_periodo_graf ],
                         [ 'name' => 'Errores', 'data' => $errores_periodo_graf ],
                     ]
                     ],
                     'tasaAciertosErroresPie' => [ // Para #TortaPorcentaje
                         'seriesData' => [
                         ['name' => 'Aciertos', 'y' => (int)($solicitudesTotales->total_ok ?? 0) ],
                         ['name' => 'Errores',  'y' => (int)($solicitudesTotales->total_error ?? 0) ],
                         ]
                     ],
                     'consumoPorApi' => [ // Para #apisConsumo
                         'categories' => $producto_graf,
                         'series' => [ ['name' => 'Consumos', 'data' => $total_registros_graf ] ]
                     ],
                     'consumoPorCliente' => [ // Para #clientesConsumo
                         'categories' => $nombre_cliente_graf,
                         'series' => [ ['name' => 'Consumos', 'data' => $consumo_total_graf ] ]
                     ],
                     'tasaErroresPorCodigo' => [ // Para #TasadeErrores
                         'categories' => $agrupado_tasa_errores_graf,
                         'series' => $series_tasa_errores_graf,
                     ],
                     'apisConMasErrores' => [ // Para #ApimasErrores
                         'categories' => $nombre_producto_errores_graf, // Nombres de productos
                         'series' => $series_errores_graf, // Array de {name: 'TipoError', data: [...]}
                     ],  
                     // ----- TIEMPO PROCESAMIENTO GRAPH - CORRECTED STRUCTURE -----
                     'tiempoProcesamiento' => [ // para #TiempoProcesamiento
                         'categories' => $mes_tiempoPromedio_categorias,
                         'series' => [
                             // The series should be an array of objects, each with 'name' and 'data'
                             ['name' => 'Tiempo Promedio (s)', 'data' => $promedio_duracion_data] 
                             // Adjust 'Tiempo Promedio (s)' if unit or name is different
                         ]
                     ],
                         'codigosRespuesta' => [ // Para #CodigosResp
                             'categories' => $codigo_resultado_graf,
                             'series' => [ ['name' => 'Cantidad', 'data' => $cantidad_Respuesta_graf] ]
                         ],
                         'apisMasLentas' => [ // Para #ApismasLentas
                             'categories' => $nombre_api_graf,
                             'series' => [ ['name' => 'Segundos', 'data' => $tiempo_api_resp_graf] ]
                         ],
                         'distribucionTiempos' => [ // Para #DistriProce
                             'categories' => $rango_tiempo_graf,
                             'series' => [ ['name' => 'Cantidad', 'data' => $cantidad_Tiempo_graf] ]
                         ],
                     'uptimeHeatmap' => $datosUptimeHeatmap
                 ]
             ];


            
           return json_encode($resultado);
        }



    /*
        Que exista, despues se mejora - TB 
    */

    public static function indexDashboardApi(){

        // Esto lo hacemos asi poque lo necesitan YA, despues se va mejorar el tema del store y los calculos - TB        
        $tiempoPromedioResp = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PROMEDIO']);        
        $solicitudesTotales = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TOTAL_CONSULTAS']);
        $totalPromedioRespuestaGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TOTAL_CONSULTAS_GRAF']);
        $totalConsultasProductGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_PRODUCT_GRAF']);
        $totalConsultasClienteGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_CLIENTE_GRAF']);
        $dataCodigoRespuesta = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CODIGO_RESP_DATA']);
        $tiempoPromedioAn = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PROM_AN']);
        $tiempoPromedioProduct = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PRODUCT']);
        $tiempoMayorMenor = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_MAYOR_MENOR']);
        $rangoTiempos = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_RANGO_TIEMPO']);
       // $codResultAnual = SQLConnection::backendStoreProcedure('api_TasaErrores',[]);
        $codResultAnual = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_COD_RESULTADOS_AN']);
        $apisMasErrores = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_APIS_MAS_ERRORES']);
        $promedioConsumoApi = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_PROD']);
        $promedioConsumoCliente = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_CLIENT']);
        
        $clientesApis = SQLConnection::backendStoreProcedure('getClientesDashboardApi',[]);
        $productosApis = SQLConnection::backendStoreProcedure('getProductosDashboardApi',[]); 

        $tiempoProce =  SQLConnection::backendStoreProcedure('api_promedioTiempoProcesamiento',[]); 
        
      //  $tiempoProce =  SQLConnection::backendStoreProcedure('api_promedioTiempoProcesamiento',['mensual',3, 92, 4405537]); 
        
        //dd($tiempoProce);

        usort($clientesApis, function ($a, $b) {
            return strcasecmp($a->nombre_cliente, $b->nombre_cliente);
        });

        usort($productosApis, function ($a, $b) {
            return strcasecmp($a->nombre_producto, $b->nombre_producto);
        });
        
        
        $mesConsultado = $tiempoPromedioResp[0]->mes_consultado ?? NULL;
        $tiempoPromedioResp = $tiempoPromedioResp[0]->segundos ?? 0;                   
        $solicitudesTotales = $solicitudesTotales[0];      
        $mesboton = $mesConsultado; 
        /** reestructuramos el total para meses, errores, ok, y totales */
        $categorias = [];
        $aciertos = [];
        $errores = [];
        $totales = [];
        $total_aciertos = 0;
        $total_errores = 0;

        foreach ($totalPromedioRespuestaGraf as $dato) {
            $mesNombre = \Carbon\Carbon::createFromFormat('Y-m', $dato->mes)->translatedFormat('M'); // Mes abreviado (Ene, Feb, etc.)
            $categorias[] = $mesNombre;
            $aciertos[] = $dato->total_ok;
            $errores[] = $dato->total_error ;
            $totales[]= $dato->total_consumos;
        }
       // dd($totalPromedioRespuestaGraf);
        foreach ($aciertos as $acierto) {
            $total_aciertos += $acierto; // Suma de los aciertos
        }
        
        foreach ($errores as $error) {
            $total_errores += $error; // Suma de los errores
        
        }
        
        /**reestructuramos para totalConsultasProductGraf  */
        $producto = [];
        $total_registros = [];
        foreach ($totalConsultasProductGraf as $dato) {
            $producto[] = $dato->nombre_producto;
            $total_registros[]= $dato->total_registros;
        }

        /**reestructuramos para totalConsultasClienteGraf */
        $nombre_cliente = [];
        $consumo_total = [];
        foreach ($totalConsultasClienteGraf as $dato) {
            $nombre_cliente[] = $dato->nombre_cliente;
            $consumo_total[]= $dato->consumo_total;
        }

        /**reestructuramos para tiempoPromedioAn */
        $mes_tiempoPromedio = [];
        $promedio_duracion = [];
        foreach ($tiempoPromedioAn as $dato) {
            $mes_tiempoPromedio[] =  \Carbon\Carbon::createFromFormat('Y-m', $dato->mes)->translatedFormat('M');
            $promedio_duracion[]= $dato->promedio_duracion;
        }

        
        /**reestructuramos para dataCodigoRespuesta */
        $codigo_resultado = [];
        $cantidad_Respuesta = [];
        foreach ($dataCodigoRespuesta as $dato) {
            $codigo_resultado[] =  $dato->codigo;
            $cantidad_Respuesta[]= $dato->cantidad;
        }        

        $tiempo_api_resp = [];
        $nombre_api = [];
        foreach ($tiempoPromedioProduct as $dato) {
            $tiempo_api_resp[] =  $dato->promedio_duracion;
            $nombre_api[]= $dato->nombre_producto;
        }
    
        /**reestructuramos para rangoTiempos */
        $rango_tiempo = [];
        $cantidad_Tiempo = [];
        foreach ($rangoTiempos as $dato) {
            $rango_tiempo[] =  $dato->rango_tiempo;
            $cantidad_Tiempo[]= $dato->cantidad;
        }            
        
        $agrupado = collect($codResultAnual)
        ->pluck('mes')
        ->map(fn($mes) => \Carbon\Carbon::createFromFormat('Y-m', $mes)->format('M'))
        ->unique()
        ->values();
    
        $codigos = collect($codResultAnual)
            ->pluck('codigo_resultado')
            ->unique()
            ->values();
        
        $erroresPorMesYCodigo = [];
        
        foreach ($agrupado as $mes) {
            foreach ($codigos as $codigo) {
                $erroresPorMesYCodigo[$codigo][$mes] = 0;
            }
        }
        
        foreach ($codResultAnual as $item) {
            $mes = \Carbon\Carbon::createFromFormat('Y-m', $item->mes)->format('M');
            $codigo = $item->codigo_resultado;
            $total = $item->total_error;
        
            $erroresPorMesYCodigo[$codigo][$mes] += $total;
        }
        
        $series = [];
        foreach ($erroresPorMesYCodigo as $codigo => $data) {
            $series[] = [
                'name' => $codigo,
                'data' => array_values($data) // Asegura orden por mes
            ];
        }                    
        
        //dd($apisMasErrores);
        $nombre_producto_errores = [];
        $errores_por_tipo = [
            'Error General' => [],
            'Internal Error' => [],
            'Error Producto' => [],
            '307' => [],
            '306' => [],
            '400' => [],
            'Internal E' => []
        ];

        foreach ($apisMasErrores as $dato) {
            $nombre_producto_errores[] = $dato->nombre_producto ?? ''; 
            // Usar valores por defecto 0 si la propiedad no existe
            $errores_por_tipo['307'][] = (int)($dato->error_307 ?? 0);
            $errores_por_tipo['306'][] = (int)($dato->error_306 ?? 0);
            $errores_por_tipo['Internal Error'][] = (int)($dato->internal_error ?? 0);
            $errores_por_tipo['Internal E'][] = (int)($dato->internal_e ?? 0);
            $errores_por_tipo['Error General'][] = (int)($dato->error_general ?? 0);
            $errores_por_tipo['Error Producto'][] = (int)($dato->error_producto ?? 0);
            $errores_por_tipo['400'][] = (int)($dato->error_400 ?? 0);
        }
        

        $subtitulo = 'ÚLTIMOS 12 MESES';

        return view('dashboard-api/dashboard')->with(compact([
            'tiempoPromedioResp',
            'solicitudesTotales',
            'totalPromedioRespuestaGraf',
            'categorias',
            'aciertos',
            'errores',
            'totales',
            'total_aciertos',
            'total_errores',
            'totalConsultasProductGraf',
            'producto',
            'total_registros',
            'totalConsultasClienteGraf',
            'nombre_cliente',
            'consumo_total',
            'dataCodigoRespuesta',
            'tiempoPromedioAn',
            'mes_tiempoPromedio',
            'promedio_duracion',
            'cantidad_Respuesta',
            'codigo_resultado',
            'tiempo_api_resp',
            'nombre_api',
            'tiempoMayorMenor',
            'rangoTiempos',
            'cantidad_Tiempo',
            'rango_tiempo',
            'codResultAnual',
            'agrupado',
            'series',
            'nombre_producto_errores',
            'errores_por_tipo',
            'promedioConsumoApi',
            'promedioConsumoCliente',
            'mesConsultado',
            'clientesApis',
            'productosApis',
            'mesboton',
            'subtitulo',
            'tiempoProce'
        ]));
    }

    /* 
        Esta funcion filtra los datos de las apis por los siguientes peroidos:
        - mensual
    */
    public static function filtroPorMes(){             
        $mes = request::input('mes');

        $totalConsultasClienteGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_CLIENTE_GRAF', NULL, $mes]);
        $totalConsultasProductGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_PRODUCT_GRAF', NULL, $mes]);
        $tiempoPromedioResp = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PROMEDIO', NULL, $mes]);
        $solicitudesTotales = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TOTAL_CONSULTAS', NULL, $mes]);
        $dataCodigoRespuesta = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CODIGO_RESP_DATA', NULL, $mes]);        
        $tiempoPromedioProduct = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PRODUCT', NULL, $mes]);        
        $tiempoMayorMenor = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_MAYOR_MENOR', NULL, $mes]);        
        $rangoTiempos = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_RANGO_TIEMPO', NULL, $mes]);        
        $apisMasErrores = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_APIS_MAS_ERRORES', NULL, $mes]);        
        $promedioConsumoApi = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_PROD', NULL, $mes]);       
        
        $promedioConsumoCliente = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_CLIENT', NULL, $mes]);       
       // dd($tiempoPromedioResp);
        /**reestructuramos para totalConsultasProductGraf  */
        $producto = [];
        $total_registros = [];
        if (!empty($totalConsultasProductGraf)) {
            foreach ($totalConsultasProductGraf as $dato) {
                $producto[] = $dato->nombre_producto;
                $total_registros[]= $dato->total_registros;
            }
        }              

        $mesConsultado = $tiempoPromedioResp[0]->mes_consultado ?? NULL;
        $tiempoPromedioResp = $tiempoPromedioResp[0]->segundos ?? 0;      

        $solicitudesTotales = $solicitudesTotales[0];
        
        /**reestructuramos para dataCodigoRespuesta */
        $codigo_resultado = [];
        $cantidad_Respuesta = [];
        if (!empty($dataCodigoRespuesta)) {
            foreach ($dataCodigoRespuesta as $dato) {
                $codigo_resultado[] =  $dato->codigo;
                $cantidad_Respuesta[]= $dato->cantidad;
            } 
        }
        
        
        $tiempo_api_resp = [];
        $nombre_api = [];
        if(!empty($tiempoPromedioProduct)){
            foreach ($tiempoPromedioProduct as $dato) {
                $tiempo_api_resp[] =  $dato->promedio_duracion;
                $nombre_api[]= $dato->nombre_producto;
            }
        }
        /**reestructuramos para rangoTiempos */
        $rango_tiempo = [];
        $cantidad_Tiempo = [];
        if(!empty($rangoTiempos)){
            foreach ($rangoTiempos as $dato) {
                $rango_tiempo[] =  $dato->rango_tiempo;
                $cantidad_Tiempo[]= $dato->cantidad;
            }
        }
        
        $nombre_producto_errores = [];
        $errores_por_tipo = [
            'Error General' => [],
            'Internal Error' => [],
            'Error Producto' => [],
            '307' => [],
            '306' => [],
            '400' => [],
            'Internal E' => []
        ];
        if(!empty($apisMasErrores)){
            foreach ($apisMasErrores as $dato) {
                $nombre_producto_errores[] = $dato->nombre_producto ?? ''; 
                // Usar valores por defecto 0 si la propiedad no existe
                $errores_por_tipo['307'][] = (int)($dato->error_307 ?? 0);
                $errores_por_tipo['306'][] = (int)($dato->error_306 ?? 0);
                $errores_por_tipo['Internal Error'][] = (int)($dato->internal_error ?? 0);
                $errores_por_tipo['Internal E'][] = (int)($dato->internal_e ?? 0);
                $errores_por_tipo['Error General'][] = (int)($dato->error_general ?? 0);
                $errores_por_tipo['Error Producto'][] = (int)($dato->error_producto ?? 0);
                $errores_por_tipo['400'][] = (int)($dato->error_400 ?? 0);
            }
        }
           /**reestructuramos para totalConsultasClienteGraf */
        $nombre_cliente = [];
        $consumo_total = [];
        if(!empty($totalConsultasClienteGraf)){
            foreach ($totalConsultasClienteGraf as $dato) {
                $nombre_cliente[] = $dato->nombre_cliente;
                $consumo_total[]= $dato->consumo_total;
            }
        }
        
        return response()->json([
            'productos' => $producto,
            'total_registros' => $total_registros,
            'totalConsultasProductGraf' => $totalConsultasProductGraf,
            'tiempoPromedioResp' => $tiempoPromedioResp,
            'solicitudesTotales' => $solicitudesTotales,
            'dataCodigoRespuesta' => $dataCodigoRespuesta,
            'cantidad_Respuesta' => $cantidad_Respuesta,
            'codigo_resultado' => $codigo_resultado,
            'tiempo_api_resp' => $tiempo_api_resp,
            'nombre_api' => $nombre_api,
            'tiempoMayorMenor' => $tiempoMayorMenor,
            'rangoTiempos' => $rangoTiempos,
            'cantidad_Tiempo' => $cantidad_Tiempo,
            'rango_tiempo' => $rango_tiempo,
            'nombre_producto_errores' => $nombre_producto_errores,
            'errores_por_tipo' => $errores_por_tipo,
            'promedioConsumoApi' => $promedioConsumoApi,
            'soymes' => $mesConsultado,
            'nombre_cliente' => $nombre_cliente,
            'consumo_total' => $consumo_total,
            'promedioConsumoCliente' => $promedioConsumoCliente
        ]);        
    }
    
    /* 
        Esta funcion filtra los datos de las apis por los siguientes peroidos:
        - diario
    */
    public static function filtroPeriodoApis(){    
        $periodo = "diario";         
        $mes = request::input('mes');

        $totalConsultasClienteGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_CLIENTE_GRAF', $periodo]);
        $totalConsultasProductGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_PRODUCT_GRAF', $periodo]);        
        $tiempoPromedioResp = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PROMEDIO', $periodo]);
        
        $solicitudesTotales = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TOTAL_CONSULTAS', $periodo]);
        
        $dataCodigoRespuesta = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CODIGO_RESP_DATA', $periodo]);        
        
        $tiempoPromedioProduct = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PRODUCT', $periodo]);        
        $tiempoMayorMenor = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_MAYOR_MENOR', $periodo]);        
        
        $rangoTiempos = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_RANGO_TIEMPO', $periodo]);        
        $apisMasErrores = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_APIS_MAS_ERRORES', $periodo]);        
        $promedioConsumoApi = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_PROD', $periodo]);               
        $promedioConsumoCliente = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_CLIENT', $periodo]);       
    
        /**reestructuramos para totalConsultasProductGraf  */
        $producto = [];
        $total_registros = [];
        if (!empty($totalConsultasProductGraf)) {
            foreach ($totalConsultasProductGraf as $dato) {
                $producto[] = $dato->nombre_producto;
                $total_registros[]= $dato->total_registros;
            }
        }                 

        $solicitudesTotales = $solicitudesTotales[0];
        
        /**reestructuramos para dataCodigoRespuesta */
        $codigo_resultado = [];
        $cantidad_Respuesta = [];
        if (!empty($dataCodigoRespuesta)) {
            foreach ($dataCodigoRespuesta as $dato) {
                $codigo_resultado[] =  $dato->codigo;
                $cantidad_Respuesta[]= $dato->cantidad;
            } 
        }
        
        
        $tiempo_api_resp = [];
        $nombre_api = [];
        if(!empty($tiempoPromedioProduct)){
            foreach ($tiempoPromedioProduct as $dato) {
                $tiempo_api_resp[] =  $dato->promedio_duracion;
                $nombre_api[]= $dato->nombre_producto;
            }
        }
        /**reestructuramos para rangoTiempos */
        $rango_tiempo = [];
        $cantidad_Tiempo = [];
        if(!empty($rangoTiempos)){
            foreach ($rangoTiempos as $dato) {
                $rango_tiempo[] =  $dato->rango_tiempo;
                $cantidad_Tiempo[]= $dato->cantidad;
            }
        }
        
        $nombre_producto_errores = [];
        $errores_por_tipo = [
            'Error General' => [],
            'Internal Error' => [],
            'Error Producto' => [],
            '307' => [],
            '306' => [],
            '400' => [],
            'Internal E' => []
        ];
        if(!empty($apisMasErrores)){
            foreach ($apisMasErrores as $dato) {
                $nombre_producto_errores[] = $dato->nombre_producto ?? ''; 
                // Usar valores por defecto 0 si la propiedad no existe
                $errores_por_tipo['307'][] = (int)($dato->error_307 ?? 0);
                $errores_por_tipo['306'][] = (int)($dato->error_306 ?? 0);
                $errores_por_tipo['Internal Error'][] = (int)($dato->internal_error ?? 0);
                $errores_por_tipo['Internal E'][] = (int)($dato->internal_e ?? 0);
                $errores_por_tipo['Error General'][] = (int)($dato->error_general ?? 0);
                $errores_por_tipo['Error Producto'][] = (int)($dato->error_producto ?? 0);
                $errores_por_tipo['400'][] = (int)($dato->error_400 ?? 0);
            }
        }
           /**reestructuramos para totalConsultasClienteGraf */
        $nombre_cliente = [];
        $consumo_total = [];
        if(!empty($totalConsultasClienteGraf)){
            foreach ($totalConsultasClienteGraf as $dato) {
                $nombre_cliente[] = $dato->nombre_cliente;
                $consumo_total[]= $dato->consumo_total;
            }
        }

        /**para colocar el dia de hoy en la vista */
        Carbon::setLocale('es'); //para que me de el mes en español 
        $hoy = Carbon::now();

        $mesConsultado = $hoy->translatedFormat('j \d\e F');
        
        return response()->json([
            'productos' => $producto,
            'total_registros' => $total_registros,
            'totalConsultasProductGraf' => $totalConsultasProductGraf,
            'tiempoPromedioResp' => $tiempoPromedioResp,
            'solicitudesTotales' => $solicitudesTotales,
            'dataCodigoRespuesta' => $dataCodigoRespuesta,
            'cantidad_Respuesta' => $cantidad_Respuesta,
            'codigo_resultado' => $codigo_resultado,
            'tiempo_api_resp' => $tiempo_api_resp,
            'nombre_api' => $nombre_api,
            'tiempoMayorMenor' => $tiempoMayorMenor,
            'rangoTiempos' => $rangoTiempos,
            'cantidad_Tiempo' => $cantidad_Tiempo,
            'rango_tiempo' => $rango_tiempo,
            'nombre_producto_errores' => $nombre_producto_errores,
            'errores_por_tipo' => $errores_por_tipo,
            'promedioConsumoApi' => $promedioConsumoApi,
            'soymes' => $mesConsultado,
            'nombre_cliente' => $nombre_cliente,
            'consumo_total' => $consumo_total,
            'promedioConsumoCliente' => $promedioConsumoCliente
            
        ]);        
    }




    public static function filtradoDatosApis(){      
        Carbon::setLocale('es'); //para que me de el mes en español     
    
        $periodo =     Request::input('periodo') ?? NULL;
        $mes =         Request::input('mes') ?? NULL;
        $productoApi = Request::input('producto') ?? NULL;
        $cliente =     Request::input('cliente') ?? NULL;        
        $dia =         Request::input('dia') ?? NULL;
        // dd($mes);

        if ($periodo == 'periodo_mensual') {    
            $periodo = 'mensual';
            $mes = NULL;
        }elseif ($periodo == 'periodo_diario') {
            $periodo = 'diario';
        }elseif ($periodo == 'periodo_actual') {
            $periodo = 'actual';        
        }       
        
         

        $solicitudesTotales = SQLConnection::backendStoreProcedure('getTotalConsultasApi', [$periodo, $mes, $productoApi, $cliente]);
        $solicitudesTotales = $solicitudesTotales[0];        


        $tiempoPromedioResp = SQLConnection::backendStoreProcedure('getTiempoPromedioApi', [$periodo, $mes, $productoApi, $cliente]);
        $tiempoPromedioResp = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PROMEDIO', $periodo, $mes, $productoApi, $cliente]);        
        $tiempoMayorMenor = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_MAYOR_MENOR', $periodo, $mes, $productoApi, $cliente]);
        $promedioConsumoApi = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_PROD', $periodo, $mes, $productoApi, $cliente]);               
        $promedioConsumoCliente = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_PROMEDIO_CONSUM_CLIENT', $periodo, $mes, $productoApi, $cliente]); 

        $totalConsultasClienteGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_CLIENTE_GRAF', $periodo, $mes, $productoApi, $cliente]);   

       // dd($cliente);
        $tiempoProce =  SQLConnection::backendStoreProcedure('api_promedioTiempoProcesamiento',[$periodo,$mes,$productoApi,$cliente]); 
       //dd($mes);
        //$tiempoProce =  SQLConnection::backendStoreProcedure('api_promedioTiempoProcesamiento',['mensual',3, 92, 4405537]);  
        //dd($tiempoProce);
        $nombre_cliente = [];
        $consumo_total = [];
        if(!empty($totalConsultasClienteGraf)){
            foreach ($totalConsultasClienteGraf as $dato) {
                $nombre_cliente[] = $dato->nombre_cliente;
                $consumo_total[]= $dato->consumo_total;
            }
        }
       
        $totalConsultasProductGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CONSULTAS_PRODUCT_GRAF', $periodo, $mes, $productoApi, $cliente]);
        $producto = [];
        $total_registros = [];
        if (!empty($totalConsultasProductGraf)) {
            foreach ($totalConsultasProductGraf as $dato) {
                $producto[] = $dato->nombre_producto;
                $total_registros[]= $dato->total_registros;
            }
        }

        $dataCodigoRespuesta = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_CODIGO_RESP_DATA', $periodo, $mes, $productoApi, $cliente]);
        $codigo_resultado = [];
        $cantidad_Respuesta = [];
        if (!empty($dataCodigoRespuesta)) {
            foreach ($dataCodigoRespuesta as $dato) {
                $codigo_resultado[] =  $dato->codigo;
                $cantidad_Respuesta[]= $dato->cantidad;
            } 
        }
        
        $tiempoPromedioProduct = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TIEMPO_PRODUCT', $periodo, $mes, $productoApi, $cliente]);
        $tiempo_api_resp = [];
        $nombre_api = [];
        if(!empty($tiempoPromedioProduct)){
            foreach ($tiempoPromedioProduct as $dato) {
                $tiempo_api_resp[] =  $dato->promedio_duracion;
                $nombre_api[]= $dato->nombre_producto;
            }
        }
        
        
        $rangoTiempos = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_RANGO_TIEMPO', $periodo, $mes, $productoApi, $cliente]);
        $rango_tiempo = [];
        $cantidad_Tiempo = [];
        if(!empty($rangoTiempos)){
            foreach ($rangoTiempos as $dato) {
                $rango_tiempo[] =  $dato->rango_tiempo;
                $cantidad_Tiempo[]= $dato->cantidad;
            }
        }        

        $apisMasErrores = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_APIS_MAS_ERRORES', $periodo, $mes, $productoApi, $cliente]);
        $nombre_producto_errores = [];
        $errores_por_tipo = [
            'Error General' => [],
            'Internal Error' => [],
            'Error Producto' => [],
            '307' => [],
            '306' => [],
            '400' => [],
            'Internal E' => []
        ];
        if(!empty($apisMasErrores)){
            foreach ($apisMasErrores as $dato) {
                $nombre_producto_errores[] = $dato->nombre_producto ?? ''; 
                // Usar valores por defecto 0 si la propiedad no existe
                $errores_por_tipo['307'][] = (int)($dato->error_307 ?? 0);
                $errores_por_tipo['306'][] = (int)($dato->error_306 ?? 0);
                $errores_por_tipo['Internal Error'][] = (int)($dato->internal_error ?? 0);
                $errores_por_tipo['Internal E'][] = (int)($dato->internal_e ?? 0);
                $errores_por_tipo['Error General'][] = (int)($dato->error_general ?? 0);
                $errores_por_tipo['Error Producto'][] = (int)($dato->error_producto ?? 0);
                $errores_por_tipo['400'][] = (int)($dato->error_400 ?? 0);
            }
        }       
        

        $totalPromedioRespuestaGraf = SQLConnection::backendStoreProcedure('BackendDashboardApi', ['GET_TOTAL_CONSULTAS_GRAF', $periodo, $mes, $productoApi, $cliente]);
        // dd($totalPromedioRespuestaGraf);
        /** reestructuramos el total para meses, errores, ok, y totales */
        $mesNombre = [];
        $categorias = [];
        $aciertos = [];
        $errores = [];
        $totales = [];
        $total_aciertos = 0;
        $total_errores = 0;
       
     //  dd($totalPromedioRespuestaGraf);
       if($periodo == 'mensual'){
        foreach ($totalPromedioRespuestaGraf as $dato) { 
            $mesNombre = \Carbon\Carbon::createFromFormat('Y-m', $dato->mes)->translatedFormat('M'); // Mes abreviado (Ene, Feb, etc.)
            $categorias[] = $mesNombre;
            $aciertos[] = $dato->total_ok;
            $errores[] = $dato->total_error ;
            $totales[]= $dato->total_consumos;
        }
       }elseif($periodo == 'diario'){
        foreach ($totalPromedioRespuestaGraf as $dato) { 
            $fecha = Carbon::createFromFormat('Y-m-d', $dato->mes);
            // Sacar el nombre del mes abreviado y el día
            $mesNombre = $fecha->translatedFormat('D d/m'); // Ej: "Abr 27"
            $categorias[] = $mesNombre;
            $aciertos[] = $dato->total_ok;
            $errores[] = $dato->total_error ;
            $totales[]= $dato->total_consumos;
        }
       }
      
        $codResultAnual = SQLConnection::backendStoreProcedure('api_TasaErrores',[$periodo, $mes, $productoApi, $cliente]);

        $campoFecha = $periodo == 'diario' ? 'dia' : 'mes';

        // Agrupar por fechas formateadas
        $agrupado = collect($codResultAnual)
            ->pluck($campoFecha)
            ->map(function ($fecha) use ($periodo) {
                return $periodo == 'diario'
                    ? Carbon::createFromFormat('Y-m-d', $fecha)->translatedFormat('D d/m') // Ej: "22 Abr"
                    : Carbon::createFromFormat('Y-m', $fecha)->translatedFormat('M');     // Ej: "Abr"
            })
            ->unique()
            ->values()
            ->all(); // <- convierte a array simple para JS
        
       // dd($agrupado); // Revisa las claves generadas
        
        // Obtener códigos únicos
        $codigos = collect($codResultAnual)
            ->pluck('codigo_resultado')
            ->unique()
            ->values()
            ->all();
        
        // Inicializar estructura de errores
        $erroresPorPeriodoYCodigo = [];
        
        foreach ($codigos as $codigo) {
            foreach ($agrupado as $fecha) {
                $erroresPorPeriodoYCodigo[$codigo][$fecha] = 0;
            }
        }
        
        // Sumar totales por código y fecha
        foreach ($codResultAnual as $item) {
            $fechaFormateada = $periodo == 'diario'
                ? Carbon::createFromFormat('Y-m-d', $item->dia)->translatedFormat('D d/m')
                : Carbon::createFromFormat('Y-m', $item->mes)->translatedFormat('M');
        
            // Debugging: Verifica el valor de fecha
           // dd($fechaFormateada); // Verifica la fecha formateada
        
            $codigo = $item->codigo_resultado;
            $total = $item->total_error;
        
            // Asegura que la fecha existe en los errores por periodo
            if (isset($erroresPorPeriodoYCodigo[$codigo][$fechaFormateada])) {
                $erroresPorPeriodoYCodigo[$codigo][$fechaFormateada] += $total;
            }
        }
        
        // Preparar series para Highcharts
        $series = [];
        
        foreach ($erroresPorPeriodoYCodigo as $codigo => $data) {
            $series[] = [
                'name' => $codigo,
                'data' => array_values($data), // Asegura el orden según agrupado
            ];
        }
        
        // Retornar la respuesta para JS
        return response()->json([
            'agrupado' => $agrupado, // etiquetas de eje X
            'series' => $series,     // datos agrupados por código
        ]);

        //dd($agrupado);
        $hoy = Carbon::yesterday();

        $mesConsultado = $hoy->translatedFormat('j \d\e F');

        $subtitulo = $periodo === 'diario' ? 'ÚLTIMOS 15 DÍAS' : 'ÚLTIMOS 12 MESES';
       //  dd($subtitulo);
        return response()->json([
            'productos' => $producto,
            'total_registros' => $total_registros,
            'totalConsultasProductGraf' => $totalConsultasProductGraf,
            'tiempoPromedioResp' => $tiempoPromedioResp,
            'solicitudesTotales' => $solicitudesTotales,
            'dataCodigoRespuesta' => $dataCodigoRespuesta,
            'cantidad_Respuesta' => $cantidad_Respuesta,
            'codigo_resultado' => $codigo_resultado,
            'tiempo_api_resp' => $tiempo_api_resp,
            'nombre_api' => $nombre_api,
            'tiempoMayorMenor' => $tiempoMayorMenor,
            'rangoTiempos' => $rangoTiempos,
            'cantidad_Tiempo' => $cantidad_Tiempo,
            'rango_tiempo' => $rango_tiempo,
            'nombre_producto_errores' => $nombre_producto_errores,
            'errores_por_tipo' => $errores_por_tipo,
            'promedioConsumoApi' => $promedioConsumoApi,
            'soymes' => $mesConsultado,
            'nombre_cliente' => $nombre_cliente,
            'consumo_total' => $consumo_total,
            'promedioConsumoCliente' => $promedioConsumoCliente,
            'periodo' => $periodo,
            'totalPromedioRespuestaGraf' => $totalPromedioRespuestaGraf,
            'categorias' => $categorias,
            'aciertos' => $aciertos,
            'errores' => $errores,
            'totales' => $totales,
            'total_aciertos' => $total_aciertos,
            'total_errores' => $total_errores,
            'subtitulo' => $subtitulo,
            'tiempoProce' => $tiempoProce,
            'agrupado' => $agrupado,
            'series' => $series

            
        ]);          

    }



    function procesarEstadisticasConsumo()
    {
        //$fecha_hoy = date('Y-m-d');
        $fecha_hoy = date('Y-m-d', strtotime('-1 day'));            
        // $db = DB::connection('dbtest'); 
    
        // $detalle = $db->select('EXEC enriqEstadisticaConsumoDetalle ?', [$fecha_hoy]);
        // $resumen = $db->select('EXEC enriqEstadisticaConsumo ?', [$fecha_hoy]);
        

        $detalle = SQLConnection::backendStoreProcedure('enriqEstadisticaConsumoDetalle', [$fecha_hoy]);
        $resumen = SQLConnection::backendStoreProcedure('enriqEstadisticaConsumo', [ $fecha_hoy]);

        return json_encode([
            'fecha' => $fecha_hoy,   // ← esto es lo que necesitás para ver la fecha desde curl
            'detalle' => $detalle,
            'resumen' => $resumen
        ]);
    }

    
    public static function cargarVistaClientesApis() {
        $clientes = Request::Input("cliente") ?? null;
        
        $resultado = SQLConnection::backendStoreProcedure('panel_clientes_api', array($clientes));
        //dd($resultado);
        // $documentosAgrupados = collect($resultado)->groupBy('nombre_cliente');
        $documentosAgrupados = [];

        foreach ($resultado as $doc) {
            // Asegurar nombre de cliente
            $cliente = $doc->nombre_cliente ?: 'Sin Nombre Cliente';

            // Agrupar por cliente
            if (!isset($documentosAgrupados[$cliente])) {
                $documentosAgrupados[$cliente] = [];
            }
            $documentosAgrupados[$cliente][] = $doc;
        }

        return view('dashboard-api/dashboard_clientes_new')->with(compact(['documentosAgrupados']));
        ;
    }

    public static function descargarExcelFiltro() {
        $cliente = Request::Input("cliente");
        //dd($cliente);
        $resultado = SQLConnection::backendStoreProcedure('panel_clientes_api', array($cliente));
        return $resultado;

    }
    
    public function descargarExcel(Request $request) {
        ini_set('max_execution_time', 300);
        function validarFecha($fecha, $formato = 'Y-m-d') {
            $d = DateTime::createFromFormat($formato, $fecha);
            return $d && $d->format($formato) === $fecha;
        }
        $cliente = Request::Input("cliente");
        $nombreCliente = Request::Input("nombrecliente");
        $productos = Request::Input('apis', []);
        $nombres_productos = Request::Input('nombres_apis', []);
        $fechaDesde = Request::Input('fecha_desde');
        $fechaHasta = Request::Input('fecha_hasta');
        $fechaDesdeArchivo = Carbon::parse($fechaDesde)->format('Ymd');
        $fechaHastaArchivo = Carbon::parse($fechaHasta)->format('Ymd');
    
        // Validación fechas
        $fechaDesdeValida = validarFecha($fechaDesde);
        $fechaHastaValida = validarFecha($fechaHasta);
    
        if (!$fechaDesdeValida && !$fechaHastaValida) {
            $fechaDesde = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
            $fechaHasta = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
        } elseif (!$fechaDesdeValida || !$fechaHastaValida) {
            return back()->with('error', 'Fechas inválidas.');
        } elseif (Carbon::parse($fechaHasta)->lt(Carbon::parse($fechaDesde))) {
            $fechaDesde = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
            $fechaHasta = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
        } else {
            $fechaDesde = Carbon::parse($fechaDesde)->startOfDay()->format('Y-m-d H:i:s');
            $fechaHasta = Carbon::parse($fechaHasta)->setTime(23, 59, 59)->format('Y-m-d H:i:s');
        }
    
        if (!$cliente || empty($productos)) {
            return back()->with('error', 'Faltan datos.');
        }
    
        // Rutas
        $nombreClienteArchivo = preg_replace('/[^A-Za-z0-9]/', '', $nombreCliente ?? '');
        $fechaDesdeArchivo = Carbon::parse($fechaDesde)->format('Ymd');
        $fechaHastaArchivo = Carbon::parse($fechaHasta)->format('Ymd');
        $fileName = 'Reporte_Api_' . $nombreClienteArchivo . '_' . $fechaDesdeArchivo . '_' . $fechaHastaArchivo . '.xml';
        $dir = env('PATH_EXCEL_API');
    
        if (!is_dir($dir)) mkdir($dir, 0777, true);
    
        $filePath = $dir . '/' . $fileName;
        $fh = fopen($filePath, 'w');
        // Cabecera XML
        fwrite($fh, <<<XML
        <?xml version="1.0"?>
        <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
        xmlns:o="urn:schemas-microsoft-com:office:office"
        xmlns:x="urn:schemas-microsoft-com:office:excel"
        xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
        xmlns:html="http://www.w3.org/TR/REC-html40">
        XML);
        //fwrite libera memoria despues de cada escritura
        foreach ($productos as $index => $productoId) {
            $nombre = $nombres_productos[$index] ?? $productoId;
            $titulo = $nombre;
            fwrite($fh, "\n  <Worksheet ss:Name=\"{$titulo}\">\n    <Table>\n");
            /* $datos = SQLConnection::backendStoreProcedure('Reporte_consumos_api_', [
                'rptagrupado',
                $cliente,
                $productoId,
                $fechaDesde,
                $fechaHasta,
                null,
            ]); */
            try {
                $datos = SQLConnection::backendStoreProcedure('Reporte_consumos_api_', [
                    'rptagrupado',
                    $cliente,
                    $productoId,
                    $fechaDesde,
                    $fechaHasta,
                    null,
                ]);
            } catch (Exception $e) {
                // Handle the error appropriately
                $datos = []; // Set to empty array or handle as needed
                Log::error('Error fetching data from stored procedure: ' . $e->getMessage());
            }
            if (!empty($datos)) {
                $cols = array_keys((array)$datos[0]);
    
                // Encabezado
                fwrite($fh, "      <Row>\n");
                foreach ($cols as $col) {
                    $colEsc = htmlspecialchars($col, ENT_QUOTES);
                    fwrite($fh, "        <Cell><Data ss:Type=\"String\">{$colEsc}</Data></Cell>\n");
                }
                fwrite($fh, "      </Row>\n");
    
                // Filas
                foreach ($datos as $fila) {
                    $fila = (array)$fila;
                    fwrite($fh, "      <Row>\n");
                    foreach ($cols as $col) {
                        $valor = $fila[$col] ?? '';
                        $tipo = is_numeric($valor) ? 'Number' : 'String';
                        $valEsc = htmlspecialchars($valor, ENT_QUOTES);
                        fwrite($fh, "        <Cell><Data ss:Type=\"{$tipo}\">{$valEsc}</Data></Cell>\n");
                    }
                    fwrite($fh, "      </Row>\n");
                }
            } else {
                fwrite($fh, "      <Row><Cell><Data ss:Type=\"String\">No hay datos</Data></Cell></Row>\n");
            }
    
            fwrite($fh, "    </Table>\n  </Worksheet>\n");
            //destruye la variable despues usarla
            unset($datos);
        }
    
        fwrite($fh, "</Workbook>");
        fclose($fh);
    
        // Forzar descarga
        $publicPath= env('PATH_EXCEL_API') . '/' . $fileName;
        return response()->download($publicPath, $fileName, [
            'Content-Type' => 'application/vnd.ms-excel',
            'Content-Disposition' => 'attachment; filename="' . str_replace('.xml', '.xls', $fileName) . '"'
        ])->deleteFileAfterSend(true);
    
    }

    public function descargarExcelFacturacion(Request $request)
    {
        $fecha_desde = Request::Input('fecha_desde_fact');
        $fecha_hasta = Request::Input('fecha_hasta_fact');
        $fechaDesde = Carbon::parse($fecha_desde)->startOfDay()->format('Y-m-d H:i:s');
        $fechaHasta = Carbon::parse($fecha_hasta)->setTime(23, 59, 59)->format('Y-m-d H:i:s');
        // Ejecutar SP
        $data = SQLConnection::backendStoreProcedure('panel_clientes_api_facturar', array(null, $fechaDesde, $fechaHasta));
    
        // Definir nombre archivo
        $fileName = 'Facturacion.xml';
        $dir = env('PATH_EXCEL_API');
    
        if (!is_dir($dir)) mkdir($dir, 0777, true);
    
        $filePath = $dir . '/' . $fileName;
        $fh = fopen($filePath, 'w');
    
        // === Cabecera XML Excel ===
        fwrite($fh, <<<XML
    <?xml version="1.0"?>
    <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
     xmlns:o="urn:schemas-microsoft-com:office:office"
     xmlns:x="urn:schemas-microsoft-com:office:excel"
     xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
     xmlns:html="http://www.w3.org/TR/REC-html40">
    XML);
    
        // === Comenzamos hoja única ===
        fwrite($fh, "\n  <Worksheet ss:Name=\"Facturacion\">\n    <Table>\n");
    
        if (!empty($data)) {
            // Columnas esperadas (keys de la BD + columna calculada)
            /* $cols = [
                'nombre_cliente',
                'nombre_producto',
                'id_producto',
                'consumo',
                'cli_codigo',
                'precio_unitario',
                'moneda',
                'desde',
                'hasta',
                'valor_facturable', // 👈 nueva columna calculada
            ]; */
            // Tomar columnas exactamente como vienen del SP
            $firstRow = (array)$data[0];
            $cols = array_keys($firstRow);
        
            // Encabezado
            fwrite($fh, "      <Row>\n");
            foreach ($cols as $col) {
                $header = htmlspecialchars($col, ENT_QUOTES);
                fwrite($fh, "        <Cell><Data ss:Type=\"String\">{$header}</Data></Cell>\n");
            }
            fwrite($fh, "      </Row>\n");
        
            // Filas de datos
            foreach ($data as $fila) {
                $fila = (array)$fila;
        
                // Calcular valor_facturable = consumo * precio_unitario
                $consumo = $fila['consumo'] ?? 0;
                $precio  = $fila['precio_unitario'] ?? 0;
                $fila['valor_facturable'] = (is_numeric($consumo) && is_numeric($precio))
                    ? $consumo * $precio
                    : 0;
        
                fwrite($fh, "      <Row>\n");
                foreach ($cols as $col) {
                    $valor = $fila[$col] ?? '';
                    $tipo = is_numeric($valor) ? 'Number' : 'String';
                    $valEsc = htmlspecialchars($valor, ENT_QUOTES);
                    fwrite($fh, "        <Cell><Data ss:Type=\"{$tipo}\">{$valEsc}</Data></Cell>\n");
                }
                fwrite($fh, "      </Row>\n");
            }
        } else {
            // No hay datos
            fwrite($fh, "      <Row><Cell><Data ss:Type=\"String\">No hay datos</Data></Cell></Row>\n");
        }
    
        fwrite($fh, "    </Table>\n  </Worksheet>\n");
        fwrite($fh, "</Workbook>");
        fclose($fh);
    
        // === Descargar como .xls (aunque el contenido sea .xml Excel-compatible) ===
        $publicPath = $filePath;
        return response()->download($publicPath, str_replace('.xml', '.xls', $fileName), [
            'Content-Type' => 'application/vnd.ms-excel',
            'Content-Disposition' => 'attachment; filename="' . str_replace('.xml', '.xls', $fileName) . '"'
        ])->deleteFileAfterSend(true);
    }

}