<?php
class SCM_api {

  // Declaración de propiedades para PHP 8.x
  public $user;
  public $password;
  public $url_base;
  public $url_auth;
  public $url_validate;
  public $url_years;
  public $url_params;
  public $url_data;
  public $categories;
  public $token;

  function __construct() {
    $this->user = carbon_get_theme_option( 'crb_admin' );
    $this->password = carbon_get_theme_option( 'crb_pass' );
    // Nueva URL base unificada según documentación
    $this->url_base = 'http://192.168.100.137:8081/simafir_api/ws/';
    $this->url_auth  = carbon_get_theme_option( 'crb_url_login' );
    $this->url_validate  = carbon_get_theme_option( 'crb_url_validate' );
    $this->url_years  = carbon_get_theme_option( 'crb_url_years' );
    $this->url_params = carbon_get_theme_option( 'crb_url_params' );
    $this->url_data = carbon_get_theme_option( 'crb_url_data' );
    $this->categories = carbon_get_theme_option( 'crb_cat' );
    $this->token = $this->getToken();
  }

  /**
   * Limpia URLs para evitar dobles slashes y normaliza el formato
   * Esta función previene errores 404 causados por // en las URLs
   * 
   * @param string $url URL completa a limpiar
   * @return string URL normalizada sin dobles slashes
   */
  private function clean_url($url) {
      // Primero, separar el esquema (http://) para no afectarlo
      $scheme = '';
      if (preg_match('~^(https?://)~i', $url, $matches)) {
          $scheme = $matches[1];
          $url = substr($url, strlen($scheme));
      }
      
      // Reemplazar múltiples slashes con uno solo
      $url = preg_replace('~/+~', '/', $url);
      
      // Reconstruir la URL con el esquema
      return $scheme . $url;
  }

  /**
   * Convierte ID de país a código SDMX para el API
   * 
   * El API de EMFA requiere códigos SDMX (ej: CR, SV, GT) en lugar de IDs numéricos
   * Esta función hace la conversión según la documentación oficial del API
   * 
   * @param int|string $countryId ID numérico del país (3, 13, 50, etc.)
   * @return string Código SDMX del país (CR, SV, GT, etc.)
   */
  private function country_id_to_sdmx($countryId) {
      // Mapeo oficial de IDs a códigos SDMX según la base de datos
      $mapping = array(
          '3'   => 'CR',  // Costa Rica
          '13'  => 'SV',  // El Salvador
          '50'  => 'GT',  // Guatemala
          '17'  => 'HN',  // Honduras
          '4'   => 'NI',  // Nicaragua
          '52'  => 'DO',  // República Dominicana
          '161' => 'PA'   // Panamá
      );
      
      // Convertir a string para comparación
      $countryId = (string) $countryId;
      
      // Si el ID existe en el mapeo, retornar código SDMX
      if (isset($mapping[$countryId])) {
          return $mapping[$countryId];
      }
      
      // Si ya es un código SDMX (2 letras mayúsculas), retornarlo tal cual
      if (preg_match('/^[A-Z]{2}$/', $countryId)) {
          return $countryId;
      }
      
      // Si no se encuentra, registrar error en debug y retornar el valor original
      error_log("SECMCA API Warning: ID de país desconocido '{$countryId}' - se usará tal cual");
      return $countryId;
  }

  /**
   * Sistema de Debug Mejorado - Almacena eventos en variable global de JavaScript
   * Solo se activa para usuarios logueados
   */
  private $debug_events = array();
  private $current_session = null;
  
  private function debug_start_session($sessionName) {
      if (!is_user_logged_in()) return;
      $this->current_session = array(
          'name' => $sessionName,
          'startTime' => microtime(true),
          'steps' => array()
      );
  }

  private function debug_add_step($stepData) {
      if (!is_user_logged_in() || !$this->current_session) return;
      
      // Agregar timestamp
      $stepData['timestamp'] = microtime(true);
      
      // Limitar el tamaño de la respuesta para evitar problemas
      if (isset($stepData['response']) && is_array($stepData['response'])) {
          // Si la respuesta es muy grande, solo guardar un resumen
          $responseSize = strlen(json_encode($stepData['response']));
          if ($responseSize > 50000) {
              $stepData['response'] = array(
                  '_summary' => 'Respuesta muy grande (' . $responseSize . ' bytes)',
                  '_keys' => array_keys($stepData['response']),
                  '_sample' => array_slice($stepData['response'], 0, 2)
              );
          }
      }
      
      $this->current_session['steps'][] = $stepData;
  }

  private function debug_end_session($status = 'success') {
      if (!is_user_logged_in() || !$this->current_session) return;
      
      $this->current_session['endTime'] = microtime(true);
      $this->current_session['duration'] = round($this->current_session['endTime'] - $this->current_session['startTime'], 3);
      $this->current_session['status'] = $status;
      
      // Agregar la sesión a la lista de eventos
      $this->debug_events[] = $this->current_session;
      $this->current_session = null;
      
      // Renderizar el evento inmediatamente en JavaScript
      $this->debug_render_event(end($this->debug_events));
  }
  
  private function debug_render_event($event) {
      $json = json_encode($event, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
      echo "\n<script>
      if (typeof window.SECMCA_DEBUG_EVENTS === 'undefined') {
          window.SECMCA_DEBUG_EVENTS = [];
      }
      window.SECMCA_DEBUG_EVENTS.push(" . $json . ");
      if (window.SECMCADebug && window.SECMCADebug.addEventFromServer) {
          window.SECMCADebug.addEventFromServer(" . $json . ");
      }
      </script>\n";
  }
  
  /**
   * Método público para renderizar todos los eventos de debug almacenados.
   * Se llama desde wp_footer para asegurar que se renderizan después de que
   * el JavaScript del debug panel esté cargado.
   */
  public function render_debug_events() {
      if (!is_user_logged_in() || empty($this->debug_events)) {
          return;
      }
      
      echo "\n<script>\n";
      echo "// SECMCA Debug Events - Generados por PHP\n";
      echo "if (typeof window.SECMCA_DEBUG_EVENTS === 'undefined') {\n";
      echo "    window.SECMCA_DEBUG_EVENTS = [];\n";
      echo "}\n";
      
      foreach ($this->debug_events as $event) {
          $json = json_encode($event, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
          echo "window.SECMCA_DEBUG_EVENTS.push(" . $json . ");\n";
      }
      
      echo "console.log('[SECMCA Debug] Eventos renderizados desde PHP:', window.SECMCA_DEBUG_EVENTS.length);\n";
      echo "</script>\n";
  }


  function getToken() {

    

    $token = $this->generate_token();
    update_option('sec_api_token', $token);
    return $token;
  }

  function generate_token() {
    $data = array(
        'user' => $this->user,
        'password' => $this->password
    );

    $payload = json_encode($data);
    // Limpiar URL de auth para evitar dobles slashes
    $auth_path = ltrim($this->url_auth, '/');
    $LOGINURL = $this->url_base . $auth_path;
    $LOGINURL = $this->clean_url($LOGINURL);
    
    $ch = curl_init($LOGINURL);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Accept: application/json',
        'Content-Type: application/json',
        'Content-Length: ' . strlen($payload)
    ));
    
    $result = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    // DEBUG: Agregar paso de autenticación al panel
    if (is_user_logged_in()) {
        $jsonToken = json_decode($result, true);
        $this->debug_add_step(array(
            'title' => '🔐 Obtener Token de Autenticación',
            'url' => $LOGINURL,
            'headers' => array(
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
                'Payload' => json_decode($payload, true)
            ),
            'httpStatus' => $http_code,
            'response' => $jsonToken ? $jsonToken : substr($result, 0, 500),
            'notes' => isset($jsonToken["JWT"]) 
                ? 'Token JWT obtenido exitosamente (longitud: ' . strlen($jsonToken["JWT"]) . ' caracteres)'
                : 'Error: No se pudo obtener el token JWT'
        ));
    }

    if (curl_errno($ch)) {
        error_log('SCM API Error: ' . curl_error($ch));
        curl_close($ch);
        return null;
    }
    curl_close($ch);
    
    $jsonToken = json_decode($result, true);
    if (isset($jsonToken["JWT"])) {
        $token = $jsonToken["JWT"];
        return $token;
    }
    
    error_log('SCM API Error: No se pudo obtener el token JWT. Response: ' . substr($result, 0, 200));
    return null;

  }

  function validate_token($token) {

      $ch            = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      $VALURL = $this->url_base . $this->url_validate;

      curl_setopt($ch, CURLOPT_URL, $VALURL);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));

      $data = curl_exec($ch);
      if (curl_errno($ch)) {
          echo "<div class='err-pop'>" . curl_error($ch) . "</div>";
          curl_close($ch);
      }
      curl_close($ch);
      if($data == 'Si tiene permiso de ver el contenido!') {
        return true;
      }
      return false;
  }

  function get_report_variables($data) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Parámetros/Criterios');
      
      $ch            = curl_init();

      // Endpoint público según documentación: /public/v1/criterios/{NOMBRE_TEMA}
      // NOTA: Este endpoint NO requiere token Bearer (es público)
      $data = ltrim($data, '/');
      $IPCURL = $this->url_base . 'public/v1/criterios/' . $data;
      
      // Limpiar URL de dobles slashes
      $IPCURL = $this->clean_url($IPCURL);

      curl_setopt($ch, CURLOPT_URL, $IPCURL);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      // NO enviar token para endpoints públicos
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json'
      ));

      $responseData = curl_exec($ch);
      if (curl_errno($ch)) {
          $error_msg = curl_error($ch);
          curl_close($ch);
          error_log('SECMCA API Error in get_report_variables: ' . $error_msg);
          
          $this->debug_add_step(array(
              'title' => '📋 Consultar Parámetros (Error de Conexión)',
              'url' => $IPCURL,
              'error' => $error_msg
          ));
          $this->debug_end_session('error');
          
          return null;
      }
      
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($responseData, true);
      
      // DEBUG: Agregar paso de consulta de parámetros
      if (is_user_logged_in()) {
          $paramsSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $keys = array_keys($myJSONArray);
              $counts = array();
              foreach ($myJSONArray as $key => $value) {
                  if (is_array($value)) {
                      $counts[] = $key . ': ' . count($value);
                  }
              }
              $paramsSummary = 'Claves: ' . implode(', ', $keys) . ' | Conteos: ' . implode(', ', $counts);
          }
          
          $this->debug_add_step(array(
              'title' => '📋 Consultar Parámetros/Criterios',
              'url' => $IPCURL,
              'headers' => array(
                  'Content-Type' => 'application/json',
                  'Token' => 'No requerido (endpoint público)'
              ),
              'httpStatus' => $http_code,
              'response' => $myJSONArray ? $myJSONArray : substr($responseData, 0, 500),
              'notes' => $paramsSummary ? $paramsSummary : 'Error al decodificar respuesta'
          ));
      }

      $myJSONArray = json_decode($responseData, true);
      
      // NUEVO: Normalizar formato de respuesta
      // La nueva API v2 retorna estructura diferente que necesita transformación
      if (is_array($myJSONArray) && isset($myJSONArray['variables'])) {
          
          // TRANSFORMAR: Mapear campos nuevos a nombres esperados por el código legacy
          $transformed = $myJSONArray;
          
          // Transformar VARIABLES: "variable" -> "nombreEsp", agregar "orden"
          if (isset($transformed['variables']) && is_array($transformed['variables'])) {
              foreach ($transformed['variables'] as $idx => &$var) {
                  // El shortcode espera "nombreEsp" pero el API envía "variable"
                  if (isset($var['variable']) && !isset($var['nombreEsp'])) {
                      $var['nombreEsp'] = $var['variable'];
                  }
                  // El shortcode espera "orden" para ordenar, usar índice como fallback
                  if (!isset($var['orden'])) {
                      $var['orden'] = $idx + 1;
                  }
              }
              unset($var); // Romper referencia
          }
          
          // Transformar PAISES: agregar "nombreEsp" y "esPais" 
          if (isset($transformed['paises']) && is_array($transformed['paises'])) {
              foreach ($transformed['paises'] as $idx => &$pais) {
                  // El shortcode espera "nombreEsp"
                  if (isset($pais['nombre']) && !isset($pais['nombreEsp'])) {
                      $pais['nombreEsp'] = $pais['nombre'];
                  }
                  // El shortcode espera "idDetalle"
                  if (isset($pais['id']) && !isset($pais['idDetalle'])) {
                      $pais['idDetalle'] = $pais['id'];
                  }
                  // Determinar si es país o región basado en el nombre
                  if (!isset($pais['esPais'])) {
                      // Si el nombre es solo siglas o dice "países", es región
                      $esRegion = (
                          strlen($pais['nombre']) <= 6 || 
                          stripos($pais['nombre'], 'países') !== false ||
                          stripos($pais['nombre'], 'américa') !== false ||
                          in_array($pais['nombre'], ['CA', 'CARD', 'CAPARD'])
                      );
                      $pais['esPais'] = $esRegion ? 'FALSE' : 'TRUE';
                  }
              }
              unset($pais); // Romper referencia
          }
          
          // Transformar FRECUENCIAS -> periocidad (renombrar clave)
          if (isset($transformed['frecuencias']) && !isset($transformed['periocidad'])) {
              $transformed['periocidad'] = $transformed['frecuencias'];
              // Mapear campos dentro de periocidad
              foreach ($transformed['periocidad'] as $idx => &$per) {
                  if (isset($per['nombre']) && !isset($per['nombreEsp'])) {
                      $per['nombreEsp'] = $per['nombre'];
                  }
                  if (isset($per['id']) && !isset($per['idDetalle'])) {
                      $per['idDetalle'] = $per['id'];
                  }
              }
              unset($per);
          }
          
          // Transformar VALORACIONES (refs/referencia) -> agregar "nombreEsp" y "idDetalle"
          if (isset($transformed['valoraciones']) && is_array($transformed['valoraciones'])) {
              foreach ($transformed['valoraciones'] as $idx => &$valoracion) {
                  if (isset($valoracion['nombre']) && !isset($valoracion['nombreEsp'])) {
                      $valoracion['nombreEsp'] = $valoracion['nombre'];
                  }
                  if (isset($valoracion['id']) && !isset($valoracion['idDetalle'])) {
                      $valoracion['idDetalle'] = $valoracion['id'];
                  }
              }
              unset($valoracion);
              
              // ALIAS: El shortcode busca "referencia" pero API envía "valoraciones"
              $transformed['referencia'] = $transformed['valoraciones'];
          }
          
          // Transformar AJUSTES: agregar "nombreEsp" y "idDetalle"
          if (isset($transformed['ajustes']) && is_array($transformed['ajustes'])) {
              foreach ($transformed['ajustes'] as $idx => &$ajuste) {
                  if (isset($ajuste['nombre']) && !isset($ajuste['nombreEsp'])) {
                      $ajuste['nombreEsp'] = $ajuste['nombre'];
                  }
                  if (isset($ajuste['id']) && !isset($ajuste['idDetalle'])) {
                      $ajuste['idDetalle'] = $ajuste['id'];
                  }
              }
              unset($ajuste);
              
              // ALIAS: El shortcode busca "ajuste" (singular) pero API envía "ajustes" (plural)
              $transformed['ajuste'] = $transformed['ajustes'];
          }
          
          // Transformar UNIDADES -> unidadMedida (renombrar clave + mapear campos)
          if (isset($transformed['unidades']) && !isset($transformed['unidadMedida'])) {
              $transformed['unidadMedida'] = $transformed['unidades'];
              foreach ($transformed['unidadMedida'] as $idx => &$unidad) {
                  if (isset($unidad['nombre']) && !isset($unidad['nombreEsp'])) {
                      $unidad['nombreEsp'] = $unidad['nombre'];
                  }
                  if (isset($unidad['id']) && !isset($unidad['idDetalle'])) {
                      $unidad['idDetalle'] = $unidad['id'];
                  }
              }
              unset($unidad);
          }
          
          // DEBUG: Agregar paso de transformación de datos
          if (is_user_logged_in()) {
              $transformSummary = 'Estructura normalizada para compatibilidad con código legacy';
              $this->debug_add_step(array(
                  'title' => '🔄 Formateo y Transformación de Datos',
                  'notes' => $transformSummary,
                  'transformed' => $transformed
              ));
          }
          
          // Envolver el objeto transformado en un array para que sea accesible como $all[0]
          $this->debug_end_session('success');
          return [$transformed];
      }
      
      $this->debug_end_session('success');
      return $myJSONArray;
  }

  function get_years($years_param, $countries_param) {
      // TEMPORAL: Endpoint /obtenerAnnos/criterios/ devuelve 401 (sin permisos)
      // Generamos años hardcodeados desde 1990 hasta el año actual
      // TODO: Restaurar llamada al API cuando el equipo resuelva los permisos del endpoint
      
      $currentYear = (int)date('Y');
      $startYear = 1990;
      
      // Generar array con estructura similar a la respuesta del API
      $myJSONArray = [];
      for ($year = $startYear; $year <= $currentYear; $year++) {
          $myJSONArray[] = [
              'datoConsulta' => (string)$year,
              'anno' => $year
          ];
      }
      
      // Retornar SOLO JSON - NO incluir echo para evitar corromper el JSON
      return json_encode($myJSONArray);
  }

  function get_years2($years_param, $countries_param) {
      // TEMPORAL: Endpoint /obtenerAnnos/criterios/ devuelve 401 (sin permisos)
      // Generamos años hardcodeados desde 1990 hasta el año actual
      // TODO: Restaurar llamada al API cuando el equipo resuelva los permisos del endpoint
      
      $currentYear = (int)date('Y');
      $startYear = 1990;
      
      // Generar array con estructura similar a la respuesta del API
      $myJSONArray = [];
      for ($year = $startYear; $year <= $currentYear; $year++) {
          $myJSONArray[] = [
              'datoConsulta' => (string)$year,
              'anno' => $year
          ];
      }
      
      // Retornar JSON codificado como lo hace el API original
      return json_encode($myJSONArray);
  }

  function get_all_data($data) {
      // ini_set('memory_limit', '-1');
      // ini_set("default_socket_timeout", 8000000);
      $token = $this->getToken();
	  
      $ch            = curl_init();

      $authorization = "Authorization: Bearer " . $token;

      // Endpoint según documentación: /public/v1/obtenerDatos/porCriterio/
      // NOTA: Este endpoint SÍ requiere token Bearer según documentación
      // Formato: {pais}/{variable}/{valoracion}/{unidad}/{frecuencia}?startPeriod=...&endPeriod=...
      $data = ltrim($data, '/');
      $IPCURL = $this->url_base . 'public/v1/obtenerDatos/porCriterio/' . $data;
      
      // Limpiar URL de dobles slashes
      $IPCURL = $this->clean_url($IPCURL);
      
      $fp = fopen(dirname(__FILE__).'/curl_err.txt', 'w');

      curl_setopt($ch, CURLOPT_URL, $IPCURL);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_TIMEOUT, 0);
      curl_setopt($ch, CURLOPT_VERBOSE, 1);
      curl_setopt($ch, CURLOPT_STDERR, $fp);
      // SÍ enviar token (requerido por este endpoint)
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      // DEBUG: Mostrar información de la consulta de datos
      if (is_user_logged_in() && function_exists('is_user_logged_in')) {
          echo "<div style='background: #e3f2fd; border-left: 4px solid #2196F3; padding: 12px; margin: 10px 0;'>";
          echo "<strong>📊 DEBUG get_all_data() - Consulta de Datos</strong><br>";
          echo "<code>URL: " . esc_html($IPCURL) . "</code><br>";
          echo "<code>HTTP Status: {$http_code}</code><br>";
          echo "<code>Response length: " . strlen($data) . " bytes</code>";
          echo "</div>";
      }

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Mostrar estructura de respuesta
      if (is_user_logged_in() && function_exists('is_user_logged_in')) {
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRegistros = count($myJSONArray);
              echo "<div style='background: #d4edda; border-left: 4px solid #28a745; padding: 12px; margin: 10px 0;'>";
              echo "<strong>✅ Datos Recibidos</strong><br>";
              echo "<code>Total registros: {$totalRegistros}</code><br>";
              
              if ($totalRegistros > 0) {
                  echo "<br><strong>📋 Primer registro (muestra):</strong><br>";
                  echo "<details style='margin-top: 8px;'>";
                  echo "<summary style='cursor: pointer; font-weight: bold;'>Ver estructura del primer registro</summary>";
                  echo "<pre style='background: #fff; padding: 8px; overflow: auto; max-height: 300px; font-size: 11px; margin-top: 8px;'>";
                  echo esc_html(json_encode($myJSONArray[0], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
                  echo "</pre>";
                  echo "</details>";
              }
              echo "</div>";
          } else {
              echo "<div style='background: #fff3cd; border-left: 4px solid #ffc107; padding: 12px; margin: 10px 0;'>";
              echo "<strong>⚠️ Sin Datos o Error</strong><br>";
              echo "<code>Response: " . esc_html(substr($data, 0, 500)) . "</code>";
              echo "</div>";
          }
      }
	  
      if($myJSONArray){
        return $myJSONArray;
      }else {
        return 'no hay datos';
      }
  }

  //guzzle function to get all data
//guzzle function to get all data
function get_all_data1($data, $client) {
    // Iniciar sesión de debug
    $this->debug_start_session('Obtener Datos con Guzzle (SIMAFIR)');
    
    $token = $this->getToken();
    
    // Limpiar barras iniciales del parámetro para evitar URLs con //
    $data = ltrim($data, '/');
    
    // **FIX CRÍTICO 1**: REORDENAR segmentos según documentación del API
    // 
    // ORDEN RECIBIDO DE App.js (ACTUALIZADO - v1.5.46):
    // Index 0: subjectID (identificador del tema, NO es el país - se descarta)
    // Index 1: fits (ajuste: N, SA, CA - NO se usa en SIMAFIR)
    // Index 2: countries (país/países: GTM, CRI, etc)
    // Index 3: vars (variables: CPI_T, etc)
    // Index 4: refs (valoración: 265, 266, etc - NO se usa en SIMAFIR)
    // Index 5: units (unidad: IX, PT, USD, etc)
    // Index 6: pers (frecuencia: M, Q, A, D)
    // Index 7+: dates (fechas/periodos: 20251, 20252, etc)
    //
    // ORDEN ESPERADO POR API SIMAFIR (sin valoración):
    // {pais} / {variable} / {unidad} / {frecuencia}
    //
    // TRANSFORMACIÓN NECESARIA:
    // [0:subjectID, 1:fits, 2:countries, 3:vars, 4:refs, 5:units, 6:pers, 7+:dates]
    //                   ↓
    // [countries, vars, refs, units, pers] + dates
    
    // Separar la URL en segmentos
    $urlParts = explode('/', $data);
    
    $this->debug_add_step(array(
        'title' => '📊 Segmentos Recibidos de JavaScript',
        'segments' => array(
            '0: subjectID' => isset($urlParts[0]) ? $urlParts[0] : 'N/A',
            '1: fits (ajuste)' => isset($urlParts[1]) ? $urlParts[1] : 'N/A',
            '2: countries (país)' => isset($urlParts[2]) ? $urlParts[2] : 'N/A',
            '3: vars (variables)' => isset($urlParts[3]) ? $urlParts[3] : 'N/A',
            '4: refs (valoración)' => isset($urlParts[4]) ? $urlParts[4] : 'N/A',
            '5: units (unidad)' => isset($urlParts[5]) ? $urlParts[5] : 'N/A',
            '6: pers (frecuencia)' => isset($urlParts[6]) ? $urlParts[6] : 'N/A',
            '7+: dates' => count($urlParts) > 7 ? implode('/', array_slice($urlParts, 7)) : 'N/A'
        )
    ));
    
    // Verificar que tengamos suficientes segmentos
    if (count($urlParts) >= 7) {
        // Extraer y transformar cada segmento
        // IMPORTANTE: El API requiere "+" para concatenar TODOS los parámetros múltiples
        // NO usar "," en ningún parámetro - ese fue el error identificado
        
        $subjectID = $urlParts[0]; // Se descarta, no va al API
        $fits = str_replace('-', '+', $urlParts[1]);      // Ajuste (N, SA, CA)
        $countries = str_replace('-', '+', $urlParts[2]); // País/países (ej: GTM, CRI)
        $vars = str_replace('-', '+', $urlParts[3]);      // Variables (ej: CPI_T)
        $refs = str_replace('-', '+', $urlParts[4]);      // Valoración (ej: 265, 266)
        $units = str_replace('-', '+', $urlParts[5]);     // Unidad (ej: IX, PT)
        $pers = str_replace('-', '+', $urlParts[6]);      // Frecuencia (ej: M, Q, A, D)
        
        // ✅ CORRECCIÓN: Mantener "+" en variables también
        // El API rechaza "," con el error: "Formato incorrecto en los parámetros enviados 
        // debe utilizar '+' para concatenar más de uno"
        // 
        // ANTES (INCORRECTO): 78,313
        // AHORA (CORRECTO):   78+313
        
        // Fechas (segmentos 7+)
        $dates = count($urlParts) > 7 ? array_slice($urlParts, 7) : array();
        
        // REORDENAR según documentación del API:
        // SIMAFIR API usa SIEMPRE: {pais}/{variable}/{unidad}/{frecuencia}
        // NO incluir valoración (refs) - ese parámetro se ignora para SIMAFIR
        
        // Construir URL sin valoración (Endpoint 2)
        // Orden: {pais}/{variable}/{unidad}/{frecuencia}
        $urlParts = array($countries, $vars, $units, $pers);
        
        // Agregar fechas al final
        if (!empty($dates)) {
            $urlParts = array_merge($urlParts, $dates);
        }
        
        $this->debug_add_step(array(
            'title' => '🔄 Segmentos Reordenados para API',
            'endpoint' => 'SIMAFIR - Sin valoración',
            'formato' => '{pais}/{variable}/{unidad}/{frecuencia}',
            'separador' => 'Todos los parámetros múltiples usan "+" (no ",")',
            'segments' => array(
                '0: pais' => $countries . ' (ej: GTM)',
                '1: variable' => $vars . ' (ej: CPI_T)',
                '2: unidad' => $units . ' (ej: IX)',
                '3: frecuencia' => $pers . ' (ej: M)',
                '4+: dates' => !empty($dates) ? implode('/', $dates) : 'N/A'
            ),
            'notas' => 'Valoración (refs=' . $refs . ') ignorada para SIMAFIR'
        ));
    }
    
    // Reconstruir la URL con los segmentos reordenados
    $data = implode('/', $urlParts);
    
    // **FIX CRÍTICO 2**: Convertir periodos del path a query parameters
    // Formato esperado por API SIMAFIR: {pais}/{variable}/{unidad}/{frecuencia}?startPeriod=dd-mm-yyyy&endPeriod=dd-mm-yyyy
    // Formato recibido AHORA (después de reordenar): {pais}/{variable}/{unidad}/{frecuencia}/{periodos-separados-por-guion}
    
    $urlParts = explode('/', $data);
    
    // SIMAFIR siempre usa 4 segmentos base: {pais}/{variable}/{unidad}/{frecuencia}
    $baseSegments = 4;
    
    // Si hay más segmentos que los base, son periodos que deben ir como query params
    if (count($urlParts) > $baseSegments) {
        // Los primeros $baseSegments son los parámetros del endpoint
        $basePath = implode('/', array_slice($urlParts, 0, $baseSegments));
        
        // Los segmentos restantes son periodos concatenados (ej: 20211-20212-20213)
        $periodosRaw = implode('/', array_slice($urlParts, $baseSegments));
        
        // Extraer periodos individuales (separados por guiones)
        $periodos = explode('-', $periodosRaw);
        $periodos = array_filter($periodos); // Remover vacíos
        
        if (!empty($periodos)) {
            // Tomar primer y último periodo
            $firstPeriod = reset($periodos);
            $lastPeriod = end($periodos);
            
            // Convertir formato YYYYM a dd-mm-yyyy
            // Ejemplo: 20211 -> 01-01-2021, 202112 -> 01-12-2021
            $startDate = $this->convertPeriodToDate($firstPeriod);
            $endDate = $this->convertPeriodToDate($lastPeriod, true); // true = último día del mes
            
            // Construir URL con query parameters según documentación
            $data = $basePath . '?startPeriod=' . $startDate . '&endPeriod=' . $endDate;
            
            $this->debug_add_step(array(
                'title' => '📅 Conversión de Fechas',
                'formato' => 'SIMAFIR: {pais}/{variable}/{unidad}/{frecuencia}',
                'basePath' => $basePath,
                'periodos' => array(
                    'primero' => $firstPeriod . ' → ' . $startDate,
                    'último' => $lastPeriod . ' → ' . $endDate
                ),
                'queryParams' => 'startPeriod=' . $startDate . '&endPeriod=' . $endDate
            ));
        } else {
            $data = $basePath;
        }
    }
    
    // Endpoint según documentación: /public/v1/obtenerDatos/porCriterio/
    // NOTA: Este endpoint SÍ requiere token Bearer
    // Formato: {pais}/{variable}/{valoracion}/{unidad}/{frecuencia}?startPeriod=...&endPeriod=...
    $fullUrl = $this->url_base . 'public/v1/obtenerDatos/porCriterio/' . $data;
    
    // Limpiar URL de dobles slashes
    $fullUrl = $this->clean_url($fullUrl);
    
    // Verificar si necesitamos usar el endpoint de tipo de cambio
    $exchangeRateInfo = $this->checkForExchangeRateVariables($data);
    if ($exchangeRateInfo) {
        $fullUrl = $this->buildExchangeRateUrl($this->url_base, $exchangeRateInfo);
    }

    // Obtener la IP del cliente para debugging - COMPATIBLE CON GUZZLE 5.x
    $isDevelopment = false;
    $host = 'unknown';
    $environment = 'PROD';
    
    try {
        // Guzzle 5.x usa getDefaultOption en lugar de getConfig
        if (method_exists($client, 'getDefaultOption')) {
            $baseUri = $client->getDefaultOption('base_url'); // Guzzle 5.x usa 'base_url'
        } elseif (method_exists($client, 'getConfig')) {
            $clientConfig = $client->getConfig();
            $baseUri = $clientConfig['base_uri'];
        } else {
            $baseUri = null;
        }
        
        if ($baseUri) {
            if (is_string($baseUri)) {
                $host = parse_url($baseUri, PHP_URL_HOST);
            } elseif (is_object($baseUri) && method_exists($baseUri, 'getHost')) {
                $host = $baseUri->getHost();
            }
            $isDevelopment = ($host === '192.168.100.137');
            $environment = $isDevelopment ? 'DEV' : 'PROD';
        }
    } catch (Exception $e) {
        // Silenciar errores de detección de ambiente
        $isDevelopment = false;
    }
   
    // SÍ enviar token (requerido por endpoint /public/v1/obtenerDatos/porCriterio/)
    $headers = [
        'Authorization' => 'Bearer ' . $token,
        'Accept'        => 'application/json',
    ];

    // DEBUG: Agregar información de la consulta al panel de debug
    $headersDebug = array();
    foreach ($headers as $key => $value) {
        if ($key === 'Authorization') {
            $headersDebug[$key] = substr($value, 0, 30) . '...' . substr($value, -15);
        } else {
            $headersDebug[$key] = $value;
        }
    }
    
    $this->debug_add_step(array(
        'title' => '🌐 Preparar Solicitud HTTP',
        'url' => $fullUrl,
        'headers' => $headersDebug,
        'environment' => $environment . ' | Host: ' . $host,
        'notes' => $exchangeRateInfo ? 
            'Tipo Cambio: Variable ' . $exchangeRateInfo['variable'] . ' | Países: ' . $exchangeRateInfo['countries'] :
            'Solicitud estándar de datos'
    ));
    
    try {
        // CAMBIO PRINCIPAL: usar get() en lugar de request() para Guzzle 5.x
        $response = $client->get($fullUrl, [
            'headers' => $headers,
            'allow_redirects' => false
        ]);
          
        $statusCode = $response->getStatusCode();
        
        // CAMBIO: En Guzzle 5.x, getBody() retorna stream, convertir a string
        $bodyContent = (string) $response->getBody();
        $bodySize = strlen($bodyContent);
        
        // PROCESAR LA RESPUESTA independientemente del status code si hay body
        if ($bodySize > 0 || $statusCode == 200 || $statusCode == 302) {
            // Intentar decodificar como JSON
            $body = json_decode($bodyContent, true);
            
            if ($body !== null && json_last_error() === JSON_ERROR_NONE) {
                $totalRegistros = is_array($body) ? count($body) : 0;
                
                // DEBUG: Agregar respuesta exitosa al panel
                $sampleData = null;
                if ($totalRegistros > 0) {
                    $sampleData = is_array($body) ? $body[0] : $body;
                }
                
                $this->debug_add_step(array(
                    'title' => '✅ Respuesta HTTP ' . $statusCode,
                    'httpStatus' => $statusCode,
                    'bodySize' => $bodySize . ' bytes',
                    'totalRecords' => $totalRegistros,
                    'response' => $sampleData,
                    'notes' => "Datos recibidos correctamente. Total de registros: {$totalRegistros}"
                ));
                
                // DEBUG: Mostrar estructura ANTES de transformar
                if (is_array($body) && count($body) > 0 && isset($body[0]['observacion'])) {
                    $this->debug_add_step(array(
                        'title' => '🔍 ESTRUCTURA DE DATOS RECIBIDA',
                        'formato' => 'SIMAFIR Nuevo (observacion array)',
                        'totalObservaciones' => count($body[0]['observacion']),
                        'primeraObservacion' => $body[0]['observacion'][0],
                        'estructuraCompleta' => array(
                            'pais' => $body[0]['pais'],
                            'variable' => $body[0]['variable'],
                            'totalObservaciones' => count($body[0]['observacion'])
                        ),
                        'notes' => 'Datos con formato nuevo de SIMAFIR - se procederá a transformar'
                    ));
                }
                
                // SIEMPRE transformar los datos para asegurar compatibilidad con el shortcode
                // La función transform_data_format detectará automáticamente el formato
                // y aplicará la transformación apropiada (SIMAFIR nuevo, desarrollo, o producción)
                $transformedData = $this->transform_data_format($body);
                
                // DEBUG: Mostrar estructura DESPUÉS de transformar
                if (is_array($transformedData) && count($transformedData) > 0) {
                    $this->debug_add_step(array(
                        'title' => '🔄 DATOS TRANSFORMADOS',
                        'totalRegistrosTransformados' => count($transformedData),
                        'primerRegistro' => $transformedData[0],
                        'camposClave' => array(
                            'paisNombreEsp' => isset($transformedData[0]['paisNombreEsp']) ? $transformedData[0]['paisNombreEsp'] : 'NO DEFINIDO',
                            'nombreEsp' => isset($transformedData[0]['nombreEsp']) ? $transformedData[0]['nombreEsp'] : 'NO DEFINIDO',
                            'anno' => isset($transformedData[0]['anno']) ? $transformedData[0]['anno'] : 'NO DEFINIDO',
                            'periodoCustom1' => isset($transformedData[0]['periodoCustom1']) ? $transformedData[0]['periodoCustom1'] : 'NO DEFINIDO',
                            'periodoCustom2' => isset($transformedData[0]['periodoCustom2']) ? $transformedData[0]['periodoCustom2'] : 'NO DEFINIDO',
                            'valorCalculado' => isset($transformedData[0]['valorCalculado']) ? $transformedData[0]['valorCalculado'] : 'NO DEFINIDO'
                        ),
                        'notes' => 'Estructura transformada lista para el shortcode'
                    ));
                    
                    // DEBUG VISIBLE: Mostrar valores directamente en la página
                    if (is_user_logged_in()) {
                        echo '<div style="background: #fff3cd; border: 2px solid #ffc107; padding: 15px; margin: 20px 0; font-family: monospace; font-size: 12px;">';
                        echo '<strong style="font-size: 14px; display: block; margin-bottom: 10px;">🔍 DEBUG: VALORES TRANSFORMADOS (Primer registro)</strong>';
                        echo '<div style="background: white; padding: 10px; border-radius: 4px;">';
                        echo '<strong>Total registros transformados:</strong> ' . count($transformedData) . '<br><br>';
                        echo '<strong>📍 Campos Clave del Primer Registro:</strong><br>';
                        echo '&nbsp;&nbsp;• <strong>paisNombreEsp:</strong> <span style="color: #d32f2f;">"' . (isset($transformedData[0]['paisNombreEsp']) ? $transformedData[0]['paisNombreEsp'] : 'NO DEFINIDO') . '"</span><br>';
                        echo '&nbsp;&nbsp;• <strong>nombreEsp:</strong> <span style="color: #d32f2f;">"' . (isset($transformedData[0]['nombreEsp']) ? $transformedData[0]['nombreEsp'] : 'NO DEFINIDO') . '"</span><br>';
                        echo '&nbsp;&nbsp;• <strong>anno:</strong> <span style="color: #1976d2;">' . (isset($transformedData[0]['anno']) ? $transformedData[0]['anno'] : 'NO DEFINIDO') . '</span><br>';
                        echo '&nbsp;&nbsp;• <strong>periodoNombreEsp:</strong> <span style="color: #d32f2f;">"' . (isset($transformedData[0]['periodoNombreEsp']) ? $transformedData[0]['periodoNombreEsp'] : 'NO DEFINIDO') . '"</span><br>';
                        echo '&nbsp;&nbsp;• <strong>periodoCustom1:</strong> <span style="color: #d32f2f;">"' . (isset($transformedData[0]['periodoCustom1']) ? $transformedData[0]['periodoCustom1'] : 'NO DEFINIDO') . '"</span><br>';
                        echo '&nbsp;&nbsp;• <strong>periodoCustom2:</strong> <span style="color: #d32f2f;">"' . (isset($transformedData[0]['periodoCustom2']) ? $transformedData[0]['periodoCustom2'] : 'NO DEFINIDO') . '"</span><br>';
                        echo '&nbsp;&nbsp;• <strong>valorCalculado:</strong> <span style="color: #388e3c; font-weight: bold;">' . (isset($transformedData[0]['valorCalculado']) ? $transformedData[0]['valorCalculado'] : 'NO DEFINIDO') . '</span><br>';
                        echo '<br><strong>🔑 Claves que la tabla buscará:</strong><br>';
                        echo '&nbsp;&nbsp;• <code>$arr["' . (isset($transformedData[0]['paisNombreEsp']) ? $transformedData[0]['paisNombreEsp'] : 'NO DEFINIDO') . '"]</code><br>';
                        echo '&nbsp;&nbsp;• <code>["1|' . (isset($transformedData[0]['nombreEsp']) ? $transformedData[0]['nombreEsp'] : 'NO DEFINIDO') . '"]</code><br>';
                        echo '&nbsp;&nbsp;• <code>["' . (isset($transformedData[0]['anno']) ? $transformedData[0]['anno'] : 'NO DEFINIDO') . '-' . (isset($transformedData[0]['periodoCustom1']) ? $transformedData[0]['periodoCustom1'] : 'NO DEFINIDO') . '"]</code><br>';
                        echo '&nbsp;&nbsp;• <code>["valorCalculado"]</code><br>';
                        echo '</div>';
                        echo '</div>';
                    }
                }
                
                $this->debug_end_session('success');
                
                return $transformedData;
            } else {
                // Error al decodificar JSON
                $errorMsg = "Error JSON: " . json_last_error_msg();
                
                // DEBUG: Agregar error JSON al panel
                $this->debug_add_step(array(
                    'title' => '❌ Error al decodificar JSON',
                    'error' => $errorMsg,
                    'httpStatus' => $statusCode,
                    'response' => substr($bodyContent, 0, 500),
                    'notes' => 'La respuesta del servidor no es JSON válido'
                ));
                
                $this->debug_end_session('error');
                
                return "No hay data - Error al procesar la respuesta JSON";
            }
        } else {
            $errorMsg = "Respuesta vacía (Status: {$statusCode})";
            
            // DEBUG: Agregar respuesta vacía al panel
            $this->debug_add_step(array(
                'title' => '⚠️ Respuesta Vacía',
                'httpStatus' => $statusCode,
                'bodySize' => $bodySize . ' bytes',
                'notes' => 'El servidor respondió pero sin contenido'
            ));
            
            $this->debug_end_session('warning');
            
            return "No hay data - {$errorMsg}";
        }
        
    } catch (GuzzleHttp\Exception\ClientException $e) {
        // 4xx errors
        $response = $e->getResponse();
        $statusCode = $response ? $response->getStatusCode() : 0;
        $errorBody = $response ? (string) $response->getBody() : '';
        
        $errorMsg = "Error {$statusCode}";
        switch ($statusCode) {
            case 404: $errorMsg .= " - Recurso no encontrado"; break;
            case 400: $errorMsg .= " - Solicitud incorrecta"; break;
            case 401: $errorMsg .= " - No autorizado"; break;
            case 403: $errorMsg .= " - Acceso prohibido"; break;
            case 422: $errorMsg .= " - Datos inválidos"; break;
        }
        
        // DEBUG: Agregar error 4xx al panel
        $responseHeaders = array();
        if ($response) {
            $rawHeaders = $response->getHeaders();
            if (!empty($rawHeaders)) {
                foreach ($rawHeaders as $key => $values) {
                    $responseHeaders[$key] = implode(', ', $values);
                }
            }
        }
        
        $this->debug_add_step(array(
            'title' => '❌ Error HTTP ' . $statusCode,
            'error' => $errorMsg,
            'httpStatus' => $statusCode,
            'requestHeaders' => $headersDebug,
            'responseHeaders' => $responseHeaders,
            'response' => substr($errorBody, 0, 1000),
            'notes' => 'Error del cliente (4xx) - Verificar parámetros de la solicitud'
        ));
        
        $this->debug_end_session('error');
        
        return "No hay data - {$errorMsg}";
        
    } catch (GuzzleHttp\Exception\ServerException $e) {
        // 5xx errors
        $response = $e->getResponse();
        $statusCode = $response ? $response->getStatusCode() : 0;
        $errorMsg = "Error servidor ({$statusCode})";
        
        // DEBUG: Agregar error 5xx al panel
        $this->debug_add_step(array(
            'title' => '❌ Error del Servidor',
            'error' => $errorMsg,
            'httpStatus' => $statusCode,
            'notes' => 'Error del servidor (5xx) - Problema en el servidor API'
        ));
        
        $this->debug_end_session('error');
        
        return "No hay data - {$errorMsg}. Intenta nuevamente más tarde.";
        
    } catch (GuzzleHttp\Exception\ConnectException $e) {
        // Problemas de conexión
        $errorMsg = "Error de conexión: " . $e->getMessage();
        
        // DEBUG: Agregar error de conexión al panel
        $this->debug_add_step(array(
            'title' => '⚠️ Error de Conexión',
            'error' => $e->getMessage(),
            'notes' => 'No se pudo establecer conexión con el servidor'
        ));
        
        $this->debug_end_session('error');
        
        return "No hay data - No se puede conectar al servidor.";
        
    } catch (GuzzleHttp\Exception\RequestException $e) {
        // Otros problemas de solicitud
        $errorMsg = "Error en solicitud: " . $e->getMessage();
        
        // DEBUG: Agregar error de solicitud al panel
        $this->debug_add_step(array(
            'title' => '❌ Error en Solicitud',
            'error' => $e->getMessage(),
            'notes' => 'Error al procesar la solicitud HTTP'
        ));
        
        $this->debug_end_session('error');
        
        return "No hay data - Error en la solicitud.";
        
    } catch (Exception $e) {
        // Captura cualquier otro error
        $errorMsg = "Error inesperado: " . $e->getMessage();
        
        // DEBUG: Agregar error inesperado al panel
        $this->debug_add_step(array(
            'title' => '❌ Error Inesperado',
            'error' => $e->getMessage(),
            'notes' => 'Error no controlado - Verificar logs del servidor'
        ));
        
        $this->debug_end_session('error');
        
        return "No hay data - Error inesperado.";
    }
    
    $this->debug_end_session('warning');
    return "No hay data disponible - Respuesta vacía del servidor.";
}

    /**
     * Convierte periodo en formato YYYYM o YYYYMM a fecha dd-mm-yyyy
     * Ejemplo: 20211 -> 01-01-2021, 202112 -> 01-12-2021
     * 
     * @param string $period Periodo en formato YYYYM o YYYYMM
     * @param bool $endOfMonth Si true, retorna el último día del mes
     * @return string Fecha en formato dd-mm-yyyy
     */
  function convertPeriodToDate($period, $endOfMonth = false) {
      // Remover cualquier carácter no numérico
      $period = preg_replace('/[^0-9]/', '', $period);
      
      if (strlen($period) < 5) {
          return '01-01-2021'; // Fecha por defecto si el formato es inválido
      }
      
      // Extraer año y mes
      if (strlen($period) == 5) {
          // Formato: YYYYM (ej: 20211 = enero 2021)
          $year = substr($period, 0, 4);
          $month = substr($period, 4, 1);
      } else {
          // Formato: YYYYMM (ej: 202112 = diciembre 2021)
          $year = substr($period, 0, 4);
          $month = substr($period, 4, 2);
      }
      
      // Asegurar que el mes tenga 2 dígitos
      $month = str_pad($month, 2, '0', STR_PAD_LEFT);
      
      // Validar mes (debe estar entre 1 y 12)
      if ($month < 1 || $month > 12) {
          $month = '01';
      }
      
      if ($endOfMonth) {
          // Obtener el último día del mes
          $day = date('t', strtotime("$year-$month-01"));
      } else {
          // Primer día del mes
          $day = '01';
      }
      
      // Retornar en formato dd-mm-yyyy
      return $day . '-' . $month . '-' . $year;
  }

  /**
     * Transforma el nuevo formato de SIMAFIR API al formato esperado por el shortcode
     * 
     * Nuevo formato API:
     * {
     *   "idVariable": "78",
     *   "variable": "CPI_T",
     *   "pais": "GTM",
     *   "observacion": [
     *     {"valor": 101.02, "periodo": "01-01-2025", "valorFormateado": "101.02"},
     *     ...
     *   ]
     * }
     * 
     * Formato esperado por shortcode:
     * [
     *   {
     *     "nombreEsp": "CPI_T",
     *     "valorCalculado": 101.02,
     *     "anno": 2025,
     *     "periodoNombreEsp": "Enero",
     *     "periodoCustom2": "1",
     *     "paisNombreEsp": "Guatemala",
     *     "paisCustom1": "GT",
     *     ...
     *   }
     * ]
     * 
     * @param array $data Los datos recibidos del API SIMAFIR
     * @return array Los datos transformados al formato del shortcode
     */
    function transform_simafir_data($data) {
        if (empty($data) || !is_array($data)) {
            return $data;
        }
        
        // Verificar si es el nuevo formato de SIMAFIR (tiene "observacion" y "variable")
        $isNewSimafirFormat = false;
        if (isset($data[0]) && isset($data[0]['observacion']) && isset($data[0]['variable'])) {
            $isNewSimafirFormat = true;
        }
        
        if (!$isNewSimafirFormat) {
            // No es el nuevo formato, retornar sin cambios
            return $data;
        }
        
        $transformedData = [];
        
        // Mapeo de códigos de país a nombres completos
        $paisNames = [
            'GTM' => 'Guatemala',
            'CRI' => 'Costa Rica',
            'SLV' => 'El Salvador',
            'HND' => 'Honduras',
            'NIC' => 'Nicaragua',
            'PAN' => 'Panamá',
            'DOM' => 'República Dominicana',
            'BLZ' => 'Belice'
        ];
        
        // Mapeo de mes (número) a nombre en español
        $mesesEsp = [
            '01' => 'Enero', '02' => 'Febrero', '03' => 'Marzo', '04' => 'Abril',
            '05' => 'Mayo', '06' => 'Junio', '07' => 'Julio', '08' => 'Agosto',
            '09' => 'Septiembre', '10' => 'Octubre', '11' => 'Noviembre', '12' => 'Diciembre'
        ];
        
        foreach ($data as $record) {
            $variable = $record['variable'];
            $paisCode = $record['pais'];
            $paisNombre = isset($paisNames[$paisCode]) ? $paisNames[$paisCode] : $paisCode;
            
            foreach ($record['observacion'] as $obs) {
                // Parsear fecha "01-01-2025" -> día-mes-año
                $fechaParts = explode('-', $obs['periodo']);
                $dia = $fechaParts[0];
                $mes = $fechaParts[1];
                $anno = $fechaParts[2];
                
                $mesNombre = isset($mesesEsp[$mes]) ? $mesesEsp[$mes] : $mes;
                
                // Crear registro en formato esperado por el shortcode
                $transformedRecord = [
                    // Campos principales (críticos para las tablas)
                    'nombreEsp' => $variable,
                    'dscEsp' => $variable,
                    'valorCalculado' => (float)$obs['valor'],
                    'anno' => (int)$anno,
                    'datoFicticio' => 'N',
                    'indDatoFicticio' => false,
                    
                    // Campos de país (críticos)
                    'paisNombreEsp' => $paisNombre,
                    'paisDscEsp' => $paisNombre,
                    'paisCustom1' => $paisCode,
                    'paisCustom3' => $this->getCountryColor($paisNombre),
                    'idPaisRegion' => $this->getCountryId($paisNombre),
                    
                    // Campos de período (críticos para ordenamiento)
                    'periodoNombreEsp' => $mesNombre,
                    'periodoCustom1' => $mesNombre,
                    'periodoCustom2' => (string)(int)$mes, // Sin cero inicial
                    'periodoCustom3' => (string)(int)$mes,
                    'periodoCustom4' => (string)(int)$mes,
                    
                    // Campos de ajuste (críticos para la estructura de datos)
                    'idAjuste' => 238,
                    'ajusteNombreEsp' => '_No aplica',
                    'ajusteCustom1' => '_Z',
                    
                    // Campos de variable y orden (críticos)
                    'idVariable' => isset($record['idVariable']) ? $record['idVariable'] : 0,
                    'ordenDespliegue' => 1,
                    'ordenamiento' => 1,
                    
                    // Campos de unidad
                    'unidadNombreEsp' => 'Índice',
                    'unidadCustom1' => 'IX',
                    
                    // Campos adicionales necesarios para compatibilidad
                    'idCarga' => 1000,
                    'idDetalleCarga' => rand(1000000, 9999999),
                    'periocidad' => 39, // Mensual
                    'estado' => 'A',
                    'derivada' => 0,
                    'formulaAplica' => 0,
                    'sector' => 226,
                    'jerarquia' => 408,
                    'escala' => 309,
                    'tipoDerivada' => 88,
                    'formula' => 0,
                    'moneda' => 286,
                    'estadoDato' => 0,
                    
                    // Campos críticos para las tablas
                    'Fictisio' => 'N',
                    'color' => $this->getCountryColor($paisNombre),
                    
                    // Metadatos adicionales del nuevo API
                    'subsector' => isset($obs['metadata']['subsector']) ? $obs['metadata']['subsector'] : 'S1',
                    'ajusteEstacional' => isset($obs['metadata']['ajusteEstacional']) ? $obs['metadata']['ajusteEstacional'] : 'N',
                    'fuente' => isset($obs['metadata']['fuente']) ? $obs['metadata']['fuente'] : 'M',
                    'valorFormateado' => isset($obs['valorFormateado']) ? $obs['valorFormateado'] : number_format($obs['valor'], 2)
                ];
                
                $transformedData[] = $transformedRecord;
            }
        }
        
        // Debug: mostrar transformación
        if (is_user_logged_in() && count($transformedData) > 0) {
            $this->debug_add_step(array(
                'title' => '🔄 Transformación de Datos SIMAFIR',
                'notasAntes' => 'Formato nuevo API: {observacion: [{valor, periodo}]}',
                'notasDespues' => 'Formato shortcode: [{nombreEsp, valorCalculado, anno, periodoNombreEsp, periodoCustom1}]',
                'totalRegistros' => count($transformedData),
                'muestra' => array_slice($transformedData, 0, 3),
                'camposClave' => array(
                    'paisNombreEsp' => $transformedData[0]['paisNombreEsp'],
                    'nombreEsp' => $transformedData[0]['nombreEsp'],
                    'anno' => $transformedData[0]['anno'],
                    'periodoNombreEsp' => $transformedData[0]['periodoNombreEsp'],
                    'periodoCustom1' => $transformedData[0]['periodoCustom1'],
                    'periodoCustom2' => $transformedData[0]['periodoCustom2'],
                    'valorCalculado' => $transformedData[0]['valorCalculado']
                )
            ));
        }
        
        return $transformedData;
    }

  /**
     * Detecta el formato de datos y los transforma al formato esperado por el código existente
     * 
     * @param array $data Los datos recibidos del API
     * @return array Los datos transformados al formato de producción
     */
    function transform_data_format($data) {
        // Verificar si los datos están vacíos
        if (empty($data) || !is_array($data)) {
            return $data;
        }
        
        // PRIMERO: Intentar transformar con el nuevo formato SIMAFIR
        $simafirTransformed = $this->transform_simafir_data($data);
        if ($simafirTransformed !== $data) {
            // Se aplicó la transformación SIMAFIR, retornar
            return $simafirTransformed;
        }
        
        // Debug: mostrar estructura de datos en desarrollo
        if (is_user_logged_in()) {
            $this->debug_data_structure($data);
        }

        // Detectar si es formato de desarrollo (estructura simplificada)
        $developmentData = null;
        
        // Verificar formato directo: [{nombrePais, variables}, {nombrePais, variables}]
        if (isset($data[0]) && isset($data[0]['nombrePais']) && isset($data[0]['variables'])) {
            $developmentData = $data;
            // Format detection log removed
        }
        // Verificar formato con un nivel de anidamiento: [[{nombrePais, variables}]]
        elseif (isset($data[0]) && isset($data[0][0]) && isset($data[0][0]['nombrePais']) && isset($data[0][0]['variables'])) {
            $developmentData = $data[0];
            // Nested format detection log removed
        }
        // Verificar formato con dos niveles: [[[{nombrePais, variables}]]]
        elseif (isset($data[0]) && isset($data[0][0]) && isset($data[0][0][0]) && isset($data[0][0][0]['nombrePais']) && isset($data[0][0][0]['variables'])) {
            $developmentData = $data[0][0];
            // Double nested format detection log removed
        }
        
        if ($developmentData !== null) {
            
            // Data transformation log removed
            
            $transformedData = [];
            
            foreach ($developmentData as $countryData) {
                $nombrePais = $countryData['nombrePais'];
                
                foreach ($countryData['variables'] as $variable) {
                    $nombreVariable = $variable['nombreVariableIndice'];
                    
                    // Variable processing log removed
                    
                    foreach ($variable['periodos'] as $periodo) {
                        // Parsear annoMes (ej: "2020-Enero")
                        $annoMesParts = explode('-', $periodo['annoMes']);
                        $anno = (int)$annoMesParts[0];
                        $mesNombre = $annoMesParts[1];
                        
                        // Mapear mes a número
                        $meses = [
                            'Enero' => 1, 'Febrero' => 2, 'Marzo' => 3, 'Abril' => 4,
                            'Mayo' => 5, 'Junio' => 6, 'Julio' => 7, 'Agosto' => 8,
                            'Septiembre' => 9, 'Octubre' => 10, 'Noviembre' => 11, 'Diciembre' => 12
                        ];
                        
                        $mesNumero = isset($meses[$mesNombre]) ? $meses[$mesNombre] : 1;
                        
                        // Crear estructura similar al formato de producción
                        $transformedRecord = [
                            // Campos principales (críticos para las tablas)
                            'nombreEsp' => $nombreVariable,
                            'dscEsp' => $nombreVariable,
                            'valorCalculado' => (float)$periodo['valorCalculado'],
                            'anno' => $anno,
                            'datoFicticio' => $periodo['Fictisio'],
                            'indDatoFicticio' => ($periodo['Fictisio'] === 'S'),
                            
                            // Campos de país (críticos)
                            'paisNombreEsp' => $nombrePais,
                            'paisDscEsp' => $nombrePais,
                            'paisCustom1' => $this->getCountryCode($nombrePais),
                            'paisCustom3' => $this->getCountryColor($nombrePais),
                            'idPaisRegion' => $this->getCountryId($nombrePais),
                            
                            // Campos de período (críticos para ordenamiento)
                            'periodoNombreEsp' => $mesNombre,
                            'periodoCustom1' => $mesNombre, // Campo importante para las tablas
                            'periodoCustom2' => (string)$mesNumero,
                            'periodoCustom3' => (string)$mesNumero,
                            'periodoCustom4' => (string)$mesNumero,
                            
                            // Campos de ajuste (críticos para la estructura de datos)
                            'idAjuste' => 238,
                            'ajusteNombreEsp' => '_No aplica',
                            'ajusteCustom1' => '_Z',
                            
                            // Campos de variable y orden (críticos)
                            'idVariable' => 797,
                            'ordenDespliegue' => 1,
                            'ordenamiento' => 1,
                            
                            // Campos de unidad
                            'unidadNombreEsp' => 'Porcentajes',
                            'unidadCustom1' => 'PT',
                            
                            // Campos adicionales necesarios para compatibilidad
                            'idCarga' => 1000,
                            'idDetalleCarga' => rand(1000000, 9999999),
                            'periocidad' => 39,
                            'estado' => 'A',
                            'derivada' => 0,
                            'formulaAplica' => 0,
                            'sector' => 226,
                            'jerarquia' => 408,
                            'escala' => 309,
                            'tipoDerivada' => 88,
                            'formula' => 0,
                            'moneda' => 286,
                            'estadoDato' => 0,
                            
                            // Campos críticos para las tablas (se necesitan para la lógica de visualización)
                            'Fictisio' => $periodo['Fictisio'], // Usado en las tablas para verificar datos ficticios
                            'color' => $this->getCountryColor($nombrePais), // Usado para colores en gráficos
                            
                            // Campos específicos para compatibilidad con tipo de cambio
                            'paisMoneda' => $nombrePais,
                            'tipoVariable' => $nombreVariable,
                            'paisMonedaColor' => $this->getCountryColor($nombrePais)
                        ];
                        
                        $transformedData[] = $transformedRecord;
                    }
                }
            }
            
            // Transformation completion log removed
            
            // Debug: Mostrar una muestra de los datos transformados
            if (count($transformedData) > 0) {
                $this->debug_table_data_construction("DATOS TRANSFORMADOS", array_slice($transformedData, 0, 2), "Muestra de 2 registros");
            }
            
            return $transformedData;
            
        } else {
            // Verificar si es formato de producción
            $isProduction = false;
            if (is_array($data) && !empty($data)) {
                // Buscar en el primer nivel de datos
                if (isset($data[0]) && is_array($data[0])) {
                    if (isset($data[0][0]) && is_array($data[0][0]) && isset($data[0][0]['idDetalleCarga'])) {
                        $isProduction = true;
                    } elseif (isset($data[0]['idDetalleCarga'])) {
                        $isProduction = true;
                    }
                }
            }
            
            // Format detection logs removed
            
            return $data;
        }
    }
    
    /**
     * Obtiene el código del país basado en su nombre
     */
    private function getCountryCode($nombrePais) {
        $countryCodes = [
            'Costa Rica' => 'CR',
            'El Salvador' => 'SV',
            'Guatemala' => 'GT',
            'Honduras' => 'HN',
            'Nicaragua' => 'NI',
            'Panamá' => 'PA',
            'República Dominicana' => 'DO',
            'Belice' => 'BZ'
        ];
        
        return isset($countryCodes[$nombrePais]) ? $countryCodes[$nombrePais] : 'XX';
    }
    
    /**
     * Obtiene el color del país basado en su nombre
     */
    private function getCountryColor($nombrePais) {
        $countryColors = [
            'Costa Rica' => '#059696',
            'El Salvador' => '#ff6b35',
            'Guatemala' => '#2e86c1',
            'Honduras' => '#28b463',
            'Nicaragua' => '#8e44ad',
            'Panamá' => '#f39c12',
            'República Dominicana' => '#e74c3c',
            'Belice' => '#17a2b8'
        ];
        
        return isset($countryColors[$nombrePais]) ? $countryColors[$nombrePais] : '#666666';
    }
    
    /**
     * Obtiene el ID del país basado en su nombre
     */
    private function getCountryId($nombrePais) {
        $countryIds = [
            'Costa Rica' => 3,
            'El Salvador' => 13,
            'Guatemala' => 50,
            'Honduras' => 17,
            'Nicaragua' => 4,
            'Panamá' => 161,
            'República Dominicana' => 52,
            'Belice' => 2
        ];
        
        return isset($countryIds[$nombrePais]) ? $countryIds[$nombrePais] : 99;
    }

    // -----EMFA----- //

  function get_charts_by_topic($api_title) {
    // Iniciar sesión de debug
    $this->debug_start_session('Obtener Gráficos por Tema (EMFA)');
    
    $token = $this->getToken();
    $ch            = curl_init();
    $authorization = "Authorization: Bearer " . $token;
    
    // Limpiar parámetro y construir URL según nueva documentación
    // Endpoint: /public/v1/emfa/criterios/{TEMA}
    $api_title = ltrim($api_title, '/');
    $url = $this->url_base . 'public/v1/emfa/criterios/' . $api_title;
    
    // Limpiar URL de dobles slashes
    $url = $this->clean_url($url);

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        $authorization
    ));
    $data = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $myJSONArray = json_decode($data, true);
    
    // DEBUG: Agregar paso de consulta de gráficos
    if (is_user_logged_in()) {
        $chartsSummary = '';
        if ($myJSONArray && is_array($myJSONArray)) {
            $totalCharts = count($myJSONArray);
            $chartsSummary = "Total de gráficos: {$totalCharts}";
            if ($totalCharts > 0 && isset($myJSONArray[0])) {
                $firstChart = $myJSONArray[0];
                $chartsSummary .= " | Primer gráfico: " . (isset($firstChart['nombre']) ? $firstChart['nombre'] : 'N/A');
            }
        }
        
        $this->debug_add_step(array(
            'title' => '📊 Consultar Gráficos por Tema',
            'url' => $url,
            'headers' => array(
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . substr($token, 0, 20) . '...'
            ),
            'httpStatus' => $http_code,
            'response' => $myJSONArray ? $myJSONArray : substr($data, 0, 500),
            'notes' => $chartsSummary ? $chartsSummary : 'Error al obtener gráficos'
        ));
    }
    
    $this->debug_end_session($myJSONArray ? 'success' : 'error');
    return $myJSONArray;
  }

  function get_chart_vars($chartID) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Variables de Gráfico (EMFA)');
      
      $token = $this->getToken();
      $ch            = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetro y construir URL
      $chartID = ltrim($chartID, '/');
      $url = $this->url_base . '/emfa/obtenerVariables/' . $chartID;
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);
      
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta de variables
      if (is_user_logged_in()) {
          $varsSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalVars = count($myJSONArray);
              $varsSummary = "Total de variables: {$totalVars}";
              if ($totalVars > 0 && isset($myJSONArray[0])) {
                  $firstVar = $myJSONArray[0];
                  $varsSummary .= " | Primera variable: " . (isset($firstVar['nombre']) ? $firstVar['nombre'] : 'N/A');
              }
          }
          
          $this->debug_add_step(array(
              'title' => '🔢 Consultar Variables del Gráfico',
              'url' => $url,
              'headers' => array(
                  'Content-Type' => 'application/json',
                  'Authorization' => 'Bearer ' . substr($token, 0, 20) . '...',
                  'Chart ID' => $chartID
              ),
              'httpStatus' => $http_code,
              'response' => $myJSONArray ? $myJSONArray : substr($data, 0, 500),
              'notes' => $varsSummary ? $varsSummary : 'Error al obtener variables'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;

  }

  function emfa_allData($chartID, $country, $years, $mouths, $peris) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Datos EMFA');
      
      $token = $this->getToken();
      $ch = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetros
      $chartID = ltrim($chartID, '/');
      $country = ltrim($country, '/');
      $years = ltrim($years, '/');
      $mouths = ltrim($mouths, '/');
      $peris = ltrim($peris, '/');
      
      // 🆕 CONVERTIR ID DE PAÍS A CÓDIGO SDMX
      // El API requiere códigos SDMX (CR, SV, GT) en lugar de IDs numéricos (3, 13, 50)
      $countryOriginal = $country; // Guardar original para debug
      $country = $this->country_id_to_sdmx($country);
      
      // NUEVA DOCUMENTACIÓN:
      // Endpoint por cuadro: /public/v1/emfa/obtenerDatos/{cuadro}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      // Endpoint por variable: /public/v1/emfa/obtenerDatos/{cuadro}/{variable}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      
      // Manejar múltiples años/meses (vienen como "2004-2005-2006" y "1-2-3-4")
      $yearArray = explode('-', $years);
      $monthArray = explode('-', $mouths);
      
      // Si hay múltiples fechas, tomar la primera y la última
      $firstYear = min($yearArray);
      $lastYear = max($yearArray);
      $firstMonth = str_pad(min($monthArray), 2, '0', STR_PAD_LEFT);
      $lastMonth = str_pad(max($monthArray), 2, '0', STR_PAD_LEFT);
      
      // Construir fechas en formato dd-mm-yyyy
      $fechaInicio = "01-{$firstMonth}-{$firstYear}"; // Primer día del mes más antiguo
      
      // Calcular último día del mes más reciente
      $ultimoDia = date('t', strtotime("{$lastYear}-{$lastMonth}-01"));
      $fechaFin = "{$ultimoDia}-{$lastMonth}-{$lastYear}";
      
      // Si hay periodos específicos (variable), usar endpoint con variable
      if ($peris != "") {
          $url = $this->url_base . 'public/v1/emfa/obtenerDatos/' . $chartID . '/' . $peris . '/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
      } else {
          // Sin variable específica, usar endpoint por cuadro
          $url = $this->url_base . 'public/v1/emfa/obtenerDatos/' . $chartID . '/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
      }
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);

      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta de datos
      if (is_user_logged_in()) {
          $dataSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRecords = count($myJSONArray);
              $dataSummary = "Total de registros: {$totalRecords}";
          }
          
          $this->debug_add_step(array(
              'title' => '📈 Consultar Datos EMFA',
              'url' => $url,
              'headers' => array(
                  'Content-Type' => 'application/json',
                  'Authorization' => 'Bearer ' . substr($token, 0, 20) . '...'
              ),
              'params' => array(
                  'Cuadro' => $chartID,
                  'País ID Original' => $countryOriginal,
                  'País SDMX' => $country,
                  'Periodo' => $fechaInicio . ' al ' . $fechaFin,
                  'Variable' => $peris ? $peris : 'Todas las variables'
              ),
              'httpStatus' => $http_code,
              'response' => $myJSONArray && count($myJSONArray) > 0 ? array_slice($myJSONArray, 0, 2) : $myJSONArray,
              'notes' => $dataSummary ? $dataSummary : 'Error al obtener datos'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;
  }

  function emfa_allData_matriz($country, $years, $mouths) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Matriz BC (EMFA)');
      
      $token = $this->getToken();
      $ch = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetros
      $country = ltrim($country, '/');
      $years = ltrim($years, '/');
      $mouths = ltrim($mouths, '/');
      
      // 🆕 CONVERTIR ID DE PAÍS A CÓDIGO SDMX
      $countryOriginal = $country;
      $country = $this->country_id_to_sdmx($country);
      
      // Manejar múltiples años/meses (vienen como "2004-2005-2006" y "1-2-3-4")
      $yearArray = explode('-', $years);
      $monthArray = explode('-', $mouths);
      
      // Si hay múltiples fechas, tomar la primera y la última
      $firstYear = min($yearArray);
      $lastYear = max($yearArray);
      $firstMonth = str_pad(min($monthArray), 2, '0', STR_PAD_LEFT);
      $lastMonth = str_pad(max($monthArray), 2, '0', STR_PAD_LEFT);
      
      // Construir fechas en formato dd-mm-yyyy
      $fechaInicio = "01-{$firstMonth}-{$firstYear}";
      $ultimoDia = date('t', strtotime("{$lastYear}-{$lastMonth}-01"));
      $fechaFin = "{$ultimoDia}-{$lastMonth}-{$lastYear}";
      
      // Endpoint: /public/v1/emfa/obtenerDatos/{cuadro}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      $url = $this->url_base . 'public/v1/emfa/obtenerDatos/BALANCE_MATRIZ_BC/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);

      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta
      if (is_user_logged_in()) {
          $dataSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRecords = count($myJSONArray);
              $dataSummary = "Total de registros: {$totalRecords}";
          }
          
          $this->debug_add_step(array(
              'title' => '🏦 Consultar Matriz BC',
              'url' => $url,
              'params' => array(
                  'Cuadro' => 'BALANCE_MATRIZ_BC',
                  'País ID Original' => $countryOriginal,
                  'País SDMX' => $country,
                  'Periodo' => $fechaInicio . ' al ' . $fechaFin
              ),
              'httpStatus' => $http_code,
              'notes' => $dataSummary ? $dataSummary : 'Error al obtener datos'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;
  }

  function emfa_allData_matriz2($country, $years, $mouths) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Matriz OSD (EMFA)');
      
      $token = $this->getToken();
      $ch = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetros
      $country = ltrim($country, '/');
      $years = ltrim($years, '/');
      $mouths = ltrim($mouths, '/');
      
      // 🆕 CONVERTIR ID DE PAÍS A CÓDIGO SDMX
      $countryOriginal = $country;
      $country = $this->country_id_to_sdmx($country);
      
      // Manejar múltiples años/meses (vienen como "2004-2005-2006" y "1-2-3-4")
      $yearArray = explode('-', $years);
      $monthArray = explode('-', $mouths);
      
      // Si hay múltiples fechas, tomar la primera y la última
      $firstYear = min($yearArray);
      $lastYear = max($yearArray);
      $firstMonth = str_pad(min($monthArray), 2, '0', STR_PAD_LEFT);
      $lastMonth = str_pad(max($monthArray), 2, '0', STR_PAD_LEFT);
      
      // Construir fechas en formato dd-mm-yyyy
      $fechaInicio = "01-{$firstMonth}-{$firstYear}";
      $ultimoDia = date('t', strtotime("{$lastYear}-{$lastMonth}-01"));
      $fechaFin = "{$ultimoDia}-{$lastMonth}-{$lastYear}";
      
      // Endpoint: /public/v1/emfa/obtenerDatos/{cuadro}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      $url = $this->url_base . 'public/v1/emfa/obtenerDatos/BALANCE_MATRIZ_OSD/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);

      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta
      if (is_user_logged_in()) {
          $dataSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRecords = count($myJSONArray);
              $dataSummary = "Total de registros: {$totalRecords}";
          }
          
          $this->debug_add_step(array(
              'title' => '🏢 Consultar Matriz OSD',
              'url' => $url,
              'params' => array(
                  'Cuadro' => 'BALANCE_MATRIZ_OSD',
                  'País ID Original' => $countryOriginal,
                  'País SDMX' => $country,
                  'Periodo' => $fechaInicio . ' al ' . $fechaFin
              ),
              'httpStatus' => $http_code,
              'notes' => $dataSummary ? $dataSummary : 'Error al obtener datos'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;
  }

  // -----ESEA----- //

  function esea_allData($newURL, $country = null, $year = null, $period = null) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Datos ESEA (Matriz)');
      
      $token = $this->getToken();
      $ch            = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetros
      $newURL = ltrim($newURL, '/');
      if ($country) $country = ltrim($country, '/');
      if ($year) $year = ltrim($year, '/');
      if ($period) $period = ltrim($period, '/');
      
      // NUEVA DOCUMENTACIÓN:
      // Endpoint por formulario: /public/v1/esea/obtenerDatos/{formulario}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      
      if($newURL == 'test1' || $newURL == 'test2' || $newURL == 'test3') {
          // Para casos especiales de matriz - necesitamos convertir year/period a fechas
          if($country && $year && $period) {
              // Manejar múltiples años/periodos si vienen concatenados
              $yearArray = explode('-', $year);
              $periodArray = explode('-', $period);
              
              // Si hay múltiples fechas, tomar la primera y la última
              $firstYear = min($yearArray);
              $lastYear = max($yearArray);
              
              // Período puede ser trimestre (I, II, III, IV) o mes
              // Asumimos que period es trimestre, convertir a mes
              $firstMonth = $this->trimesterToMonth(min($periodArray), true); // mes inicio
              $lastMonth = $this->trimesterToMonth(max($periodArray), false); // mes fin
              
              // Construir fechas en formato dd-mm-yyyy
              $fechaInicio = "01-{$firstMonth}-{$firstYear}";
              $ultimoDia = date('t', strtotime("{$lastYear}-{$lastMonth}-01"));
              $fechaFin = "{$ultimoDia}-{$lastMonth}-{$lastYear}";
              
              $url = $this->url_base . 'public/v1/esea/obtenerDatos/' . $newURL . '/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
          } else {
              $url = $this->url_base . 'public/v1/esea/obtenerDatos/' . $newURL;
          }
      } else {
          $url = $this->url_base . 'public/v1/esea/obtenerDatos/' . $newURL;
      }
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);
      
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta
      if (is_user_logged_in()) {
          $dataSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRecords = count($myJSONArray);
              $dataSummary = "Total de registros: {$totalRecords}";
          }
          
          $debugParams = array('Formulario' => $newURL);
          if ($country) {
              $debugParams['País'] = $country;
              if (isset($fechaInicio) && isset($fechaFin)) {
                  $debugParams['Periodo'] = $fechaInicio . ' al ' . $fechaFin;
              }
          }
          
          $this->debug_add_step(array(
              'title' => '🗂️ Consultar Datos ESEA (Matriz)',
              'url' => $url,
              'params' => $debugParams,
              'httpStatus' => $http_code,
              'notes' => $dataSummary ? $dataSummary : 'Error al obtener datos'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;

  }
  
  // Helper function para convertir trimestre a mes
  private function trimesterToMonth($trimester, $isStart = true) {
      $trimesterMap = array(
          '1' => $isStart ? '01' : '03',  // Q1: Enero-Marzo
          'I' => $isStart ? '01' : '03',
          '2' => $isStart ? '04' : '06',  // Q2: Abril-Junio
          'II' => $isStart ? '04' : '06',
          '3' => $isStart ? '07' : '09',  // Q3: Julio-Septiembre
          'III' => $isStart ? '07' : '09',
          '4' => $isStart ? '10' : '12',  // Q4: Octubre-Diciembre
          'IV' => $isStart ? '10' : '12'
      );
      
      return isset($trimesterMap[$trimester]) ? $trimesterMap[$trimester] : '01';
  }

  function esea_allData2($country,$finaldates,$newURL) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Datos ESEA');
      
      $token = $this->getToken();
      $ch            = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetros
      $country = ltrim($country, '/');
      $finaldates = ltrim($finaldates, '/');
      $newURL = ltrim($newURL, '/');
      
      // NUEVA DOCUMENTACIÓN:
      // Endpoint por formulario: /public/v1/esea/obtenerDatos/{formulario}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      // Endpoint por variable: /public/v1/esea/obtenerDatos/{formulario}/{variable}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
      
      // $finaldates puede venir en formato: "01-01-2020/31-12-2020" o años/meses múltiples
      if (strpos($finaldates, '/') !== false) {
          // Ya viene con formato fechaInicio/fechaFin
          list($fechaInicio, $fechaFin) = explode('/', $finaldates);
      } else {
          // Puede ser formato año/mes simple
          $fechaInicio = $finaldates;
          $fechaFin = $finaldates;
      }
      
      // Detectar si $newURL contiene una variable (más de un segmento)
      // Si tiene "/" es formulario/variable
      if (strpos($newURL, '/') !== false) {
          // Endpoint con variable específica
          $url = $this->url_base . 'public/v1/esea/obtenerDatos/' . $newURL . '/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
      } else {
          // Endpoint por formulario
          $url = $this->url_base . 'public/v1/esea/obtenerDatos/' . $newURL . '/' . $country . '?fechaInicio=' . $fechaInicio . '&fechaFin=' . $fechaFin;
      }
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);
      
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta de datos
      if (is_user_logged_in()) {
          $dataSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRecords = count($myJSONArray);
              $dataSummary = "Total de registros: {$totalRecords}";
          }
          
          $this->debug_add_step(array(
              'title' => '📊 Consultar Datos ESEA',
              'url' => $url,
              'headers' => array(
                  'Content-Type' => 'application/json',
                  'Authorization' => 'Bearer ' . substr($token, 0, 20) . '...'
              ),
              'params' => array(
                  'Formulario/Variable' => $newURL,
                  'País' => $country,
                  'Periodo' => $fechaInicio . ' al ' . $fechaFin
              ),
              'httpStatus' => $http_code,
              'notes' => $dataSummary ? $dataSummary : 'Error al obtener datos'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;
      

  }

  function esea_get_params($subject) {
      // Iniciar sesión de debug
      $this->debug_start_session('Obtener Parámetros ESEA');
      
      $token = $this->getToken();
      $ch            = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      
      // Limpiar parámetro
      $subject = ltrim($subject, '/');
      
      // NUEVA DOCUMENTACIÓN:
      // Endpoint: /public/v1/esea/criterios/{TEMA}
      $url = $this->url_base . 'public/v1/esea/criterios/' . $subject;
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);
      
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);
    
      $myJSONArray = json_decode($data, true);
      
      // DEBUG: Agregar paso de consulta
      if (is_user_logged_in()) {
          $dataSummary = '';
          if ($myJSONArray && is_array($myJSONArray)) {
              $totalRecords = count($myJSONArray);
              $dataSummary = "Total de formularios: {$totalRecords}";
          }
          
          $this->debug_add_step(array(
              'title' => '📋 Consultar Formularios ESEA',
              'url' => $url,
              'params' => array(
                  'Tema' => $subject
              ),
              'httpStatus' => $http_code,
              'notes' => $dataSummary ? $dataSummary : 'Error al obtener parámetros'
          ));
      }
      
      $this->debug_end_session($myJSONArray ? 'success' : 'error');
      return $myJSONArray;

  }
	
	
	 function esea_get_available() {
    $token = $this->getToken();
      $ch            = curl_init();
      $authorization = "Authorization: Bearer " . $token;
      // Usar URL base unificada - EMFA endpoint
      $url = $this->url_base . 'public/v1/emfa/obtenerDatosRecientes';
      
      // Limpiar URL de dobles slashes
      $url = $this->clean_url($url);
      
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
          'Content-Type: application/json',
          $authorization
      ));
      $data = curl_exec($ch);
      curl_close($ch);

      $myJSONArray = json_decode($data, true);
      return $myJSONArray;
  }
	
	/**
     * Función de debug para analizar la estructura de datos
     * Solo se ejecuta en desarrollo
     */
    function debug_data_structure($data, $maxDepth = 3) {
         return;
    }
    
    /**
     * Función recursiva para analizar la estructura de un array
     */
    private function analyze_array_structure($data, $level = 0, $maxDepth = 3) {
        if ($level > $maxDepth) {
            echo "<div style='margin-left: " . ($level * 20) . "px; color: #6c757d;'>... (máxima profundidad alcanzada)</div>";
            return;
        }
        
        $indent = str_repeat("&nbsp;&nbsp;&nbsp;&nbsp;", $level);
        
        if (is_array($data)) {
            $count = count($data);
            $isAssoc = $this->is_assoc_array($data);
            $arrayType = $isAssoc ? "Asociativo" : "Índice";
            
            echo "<div style='margin-left: " . ($level * 20) . "px;'>";
            echo "<strong>📋 Array {$arrayType}</strong> <span style='color: #6c757d;'>({$count} elementos)</span>";
            
            if ($count > 0) {
                // Mostrar algunos elementos clave
                $keys = array_keys($data);
                if ($count <= 5) {
                    foreach ($keys as $key) {
                        echo "<br>{$indent}├── <code style='background: #e9ecef; padding: 2px 4px; border-radius: 3px;'>[{$key}]</code>";
                        if (is_array($data[$key])) {
                            echo " → ";
                            $this->analyze_array_structure($data[$key], $level + 1, $maxDepth);
                        } else {
                            $type = gettype($data[$key]);
                            $value = is_string($data[$key]) ? '"' . substr($data[$key], 0, 50) . (strlen($data[$key]) > 50 ? '...' : '') . '"' : $data[$key];
                            echo " <span style='color: #28a745;'>({$type})</span> <span style='color: #6c757d;'>{$value}</span>";
                        }
                    }
                } else {
                    // Mostrar solo los primeros elementos si hay muchos
                    for ($i = 0; $i < 3; $i++) {
                        if (isset($keys[$i])) {
                            $key = $keys[$i];
                            echo "<br>{$indent}├── <code style='background: #e9ecef; padding: 2px 4px; border-radius: 3px;'>[{$key}]</code>";
                            if (is_array($data[$key])) {
                                echo " → ";
                                $this->analyze_array_structure($data[$key], $level + 1, $maxDepth);
                            } else {
                                $type = gettype($data[$key]);
                                $value = is_string($data[$key]) ? '"' . substr($data[$key], 0, 30) . (strlen($data[$key]) > 30 ? '...' : '') . '"' : $data[$key];
                                echo " <span style='color: #28a745;'>({$type})</span> <span style='color: #6c757d;'>{$value}</span>";
                            }
                        }
                    }
                    echo "<br>{$indent}└── <span style='color: #6c757d;'>... y " . ($count - 3) . " elementos más</span>";
                }
            }
            echo "</div>";
        } else {
            $type = gettype($data);
            echo "<div style='margin-left: " . ($level * 20) . "px;'>";
            echo "<span style='color: #dc3545;'>No es un array:</span> <span style='color: #28a745;'>({$type})</span> {$data}";
            echo "</div>";
        }
    }
    
    /**
     * Verifica si un array es asociativo
     */
    private function is_assoc_array($array) {
        if (!is_array($array) || empty($array)) {
            return false;
        }
        return array_keys($array) !== range(0, count($array) - 1);
    }

    /**
     * Función de debug temporal para rastrear cómo se construyen los datos de las tablas
     * Solo funciona en desarrollo
     */
    function debug_table_data_construction($stage, $data, $context = '') {
        // Debug function disabled - logs removed
        return;
    }

    /**
     * Verifica si la URL contiene variables de tipo de cambio (54, 55, 56)
     * y extrae la información necesaria para construir el endpoint alternativo
     * 
     * @param string $data Los parámetros de la URL
     * @return array|false Array con información para tipo de cambio o false si no aplica
     */
private function checkForExchangeRateVariables($data) {
    $exchangeRateVariables = ['54', '55', '56'];
    $urlSegments = explode('/', trim($data, '/'));
    
    // Índice fijo donde deben estar las variables de tipo de cambio
    $exchangeRateIndex = 6; // Séptimo chunk (empezando desde 0)
    
    // Verificar que el índice existe
    if (!isset($urlSegments[$exchangeRateIndex])) {
        return false;
    }
    
    $segment = $urlSegments[$exchangeRateIndex];
    
    // Separar las variables del segmento (pueden estar separadas por guión)
    $variables = strpos($segment, '-') !== false ? explode('-', $segment) : [$segment];
    
    // Encontrar todas las variables de tipo de cambio en este segmento
    $exchangeRateVarsFound = [];
    foreach ($variables as $variable) {
        if (in_array($variable, $exchangeRateVariables)) {
            $exchangeRateVarsFound[] = $variable;
        }
    }
    
    // Si no encontramos ninguna variable de tipo de cambio, retornar false
    if (empty($exchangeRateVarsFound)) {
        return false;
    }
    
    $selectedVariables = implode('-', $exchangeRateVarsFound);
    
    // Buscar el segmento de países (segmentos anteriores con números separados por guión)
    $countries = '';
    $maxCountriesCount = 0;
    
    for ($i = 0; $i < $exchangeRateIndex; $i++) {
        if (strpos($urlSegments[$i], '-') !== false) {
            $segmentParts = explode('-', $urlSegments[$i]);
            $isNumericSegment = true;
            
            foreach ($segmentParts as $part) {
                if (!is_numeric($part)) {
                    $isNumericSegment = false;
                    break;
                }
            }
            
            if ($isNumericSegment && count($segmentParts) > $maxCountriesCount) {
                $countries = $urlSegments[$i];
                $maxCountriesCount = count($segmentParts);
            }
        }
    }
    
    // Extraer fechas (deben estar después del índice de tipo de cambio)
    $dateStart = isset($urlSegments[$exchangeRateIndex + 1]) ? $urlSegments[$exchangeRateIndex + 1] : '';
    $dateEnd = isset($urlSegments[$exchangeRateIndex + 2]) ? $urlSegments[$exchangeRateIndex + 2] : '';
    
    return [
        'variable' => $selectedVariables,
        'countries' => $countries,
        'dateStart' => $dateStart,
        'dateEnd' => $dateEnd,
        'allVariables' => $variables,
        'exchangeRateVarsFound' => $exchangeRateVarsFound,
        'segmentIndex' => $exchangeRateIndex
    ];
}

    /**
     * Construye la URL del endpoint de tipo de cambio según nueva documentación
     * Endpoint: /public/v1/tipoCambioExterno/obtenerDatos/{variable}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
     * 
     * @param string $baseUrl URL base
     * @param array $exchangeInfo Información extraída de checkForExchangeRateVariables
     * @return string URL completa del endpoint de tipo de cambio
     */
    private function buildExchangeRateUrl($baseUrl, $exchangeInfo) {
        // Mapeo de IDs de variables a códigos de la nueva API
        $variableIdToCode = [
            '54' => 'NER',    // Tipo de cambio oficial
            '55' => 'NER_B',  // Tipo de cambio compra
            '56' => 'NER_S'   // Tipo de cambio venta
        ];
        
        // Mapeo de IDs de países a códigos
        $countryIdToCode = [
            '3' => 'CR',    // Costa Rica
            '13' => 'SV',   // El Salvador
            '17' => 'HN',   // Honduras
            '4' => 'NI',    // Nicaragua
            '50' => 'GT',   // Guatemala
            '52' => 'DO',   // República Dominicana
            '161' => 'PA',  // Panamá
            '2' => 'BZ'     // Belice
        ];
        
        // Convertir ID de variable a código (usar la primera variable encontrada)
        $variableIds = explode('-', $exchangeInfo['variable']);
        $variableCode = isset($variableIdToCode[$variableIds[0]]) ? $variableIdToCode[$variableIds[0]] : 'NER';
        
        // Procesar todos los países de la lista
        $countryIds = explode('-', $exchangeInfo['countries']);
        $countryCodes = [];
        
        foreach ($countryIds as $countryId) {
            $countryCode = isset($countryIdToCode[$countryId]) ? $countryIdToCode[$countryId] : 'CR';
            $countryCodes[] = $countryCode;
        }
        
        // Unir todos los códigos de países con guiones
        $finalCountryCode = implode('-', $countryCodes);
        
        // Formatear fechas en formato dd-mm-yyyy
        $dateStart = $this->formatDateForExchangeRate($exchangeInfo['dateStart']);
        $dateEnd = $this->formatDateForExchangeRate($exchangeInfo['dateEnd']);
        
        // Construir URL según nueva documentación:
        // /public/v1/tipoCambioExterno/obtenerDatos/{variable}/{pais}?fechaInicio=dd-mm-yyyy&fechaFin=dd-mm-yyyy
        $exchangeRateUrl = $baseUrl . 'public/v1/tipoCambioExterno/obtenerDatos/' . $variableCode . '/' . $finalCountryCode;
        
        // Agregar parámetros de fecha si existen
        if (!empty($dateStart) && !empty($dateEnd)) {
            $exchangeRateUrl .= '?fechaInicio=' . $dateStart . '&fechaFin=' . $dateEnd;
        }
        
        return $exchangeRateUrl;
    }

    /**
     * Formatea fechas para el endpoint de tipo de cambio
     * 
     * @param string $date Fecha en cualquier formato
     * @return string Fecha en formato DD-MM-YYYY (requerido por la API)
     */
    private function formatDateForExchangeRate($date) {
        // Si la fecha está vacía, devolverla tal como está
        if (empty($date)) {
            return $date;
        }
        
        // Si ya está en formato DD-MM-YYYY, devolverla tal como está
        if (preg_match('/^(\d{2})-(\d{2})-(\d{4})$/', $date)) {
            return $date;
        }
        
        // Si está en formato YYYY-MM-DD, convertir a DD-MM-YYYY
        if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $date, $matches)) {
            return $matches[3] . '-' . $matches[2] . '-' . $matches[1];
        }
        
        // Si no se puede parsear, devolver tal como está
        return $date;
    }

    /* ========================================
       EFPA - Estadísticas de Finanzas Públicas Armonizadas
       ======================================== */

    /**
     * Genera un token específico para EFPA usando el servidor de desarrollo
     * @return string|null
     */
    private function efpa_generate_token() {
        $data = array(
            'user' => $this->user,
            'password' => $this->password
        );

        $payload = json_encode($data);
        $LOGINURL = 'http://192.168.100.137:8081/simafir_api/ws/auth/login';
        $ch = curl_init($LOGINURL);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLINFO_HEADER_OUT, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Content-Length: ' . strlen($payload)
        ));
        $result = curl_exec($ch);

        if (curl_errno($ch)) {
            error_log('EFPA Token Error: ' . curl_error($ch));
            curl_close($ch);
            return null;
        }
        curl_close($ch);
        
        $jsonToken = json_decode($result, true);
        if (isset($jsonToken["JWT"])) {
            return $jsonToken["JWT"];
        }
        
        error_log('EFPA Token Error: No se pudo obtener el token JWT. Response: ' . $result);
        return null;
    }

    /**
     * Obtiene o genera el token para EFPA
     * @return string|null
     */
    private function efpa_get_token() {
        // Intentar obtener el token cacheado
        $cached_token = get_transient('efpa_api_token');
        
        if ($cached_token) {
            return $cached_token;
        }
        
        // Si no hay token cacheado, generar uno nuevo
        $token = $this->efpa_generate_token();
        
        if ($token) {
            // Cachear el token por 30 minutos
            set_transient('efpa_api_token', $token, 30 * MINUTE_IN_SECONDS);
        }
        
        return $token;
    }

    /**
     * Obtiene la lista de cuadros disponibles en EFPA
     * @return array|null
     */
    function efpa_get_cuadros() {
        $url = 'http://192.168.100.137:8081/simafir_api/ws/efpa/criterios/obtenerCuadros?formato=json';
        
        $token = $this->efpa_get_token();
        
        if (!$token) {
            error_log('EFPA API Error: No se pudo obtener el token de autenticación');
            if (is_user_logged_in()) {
                echo "<div style='background:#f8d7da;border:1px solid #f5c6cb;padding:12px;margin:10px 0;border-radius:4px;'>";
                echo "<strong>🔴 Error de Autenticación:</strong> No se pudo generar el token para EFPA<br>";
                echo "<strong>Verifica:</strong> Usuario y contraseña en Theme Options";
                echo "</div>";
            }
            return null;
        }
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Authorization: Bearer ' . $token
        ));
        
        $result = curl_exec($ch);
        
        if (curl_errno($ch)) {
            $error = 'EFPA API Error (obtenerCuadros): ' . curl_error($ch);
            error_log($error);
            if (is_user_logged_in()) {
                echo "<div style='background:#f8d7da;border:1px solid #f5c6cb;padding:12px;margin:10px 0;border-radius:4px;'>";
                echo "<strong>🔴 CURL Error:</strong> " . curl_error($ch) . "<br>";
                echo "<strong>URL:</strong> <code>{$url}</code>";
                echo "</div>";
            }
            curl_close($ch);
            return null;
        }
        
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($http_code !== 200) {
            $error = 'EFPA API HTTP Error: Code ' . $http_code . ' for obtenerCuadros. Response: ' . $result;
            error_log($error);
            if (is_user_logged_in()) {
                echo "<div style='background:#fff3cd;border:1px solid #ffeaa7;padding:12px;margin:10px 0;border-radius:4px;'>";
                echo "<strong>⚠️ HTTP Error {$http_code}</strong><br>";
                echo "<strong>URL:</strong> <code>{$url}</code><br>";
                echo "<strong>Response:</strong><br><pre style='background:#fff;padding:8px;border-radius:3px;font-size:11px;max-height:200px;overflow:auto;'>" . htmlspecialchars($result) . "</pre>";
                echo "</div>";
            }
            return null;
        }
        
        $data = json_decode($result, true);
        
        if (!is_array($data)) {
            $error = 'EFPA API Error: obtenerCuadros no retornó un array válido. Response: ' . $result;
            error_log($error);
            if (is_user_logged_in()) {
                echo "<div style='background:#f8d7da;border:1px solid #f5c6cb;padding:12px;margin:10px 0;border-radius:4px;'>";
                echo "<strong>❌ JSON Parse Error</strong><br>";
                echo "<strong>Response received:</strong><br><pre style='background:#fff;padding:8px;border-radius:3px;font-size:11px;max-height:200px;overflow:auto;'>" . htmlspecialchars(substr($result, 0, 500)) . "</pre>";
                echo "</div>";
            }
            return null;
        }
        
        // Mostrar éxito en desarrollo (COMENTADO - Desactivar para producción)
        /*
        if (is_user_logged_in()) {
            echo "<div style='background:#d4edda;border:1px solid #c3e6cb;padding:12px;margin:10px 0;border-radius:4px;'>";
            echo "<strong>✅ Cuadros EFPA cargados exitosamente</strong><br>";
            echo "<strong>URL:</strong> <code>{$url}</code><br>";
            echo "<strong>Total de cuadros:</strong> " . count($data);
            echo "</div>";
        }
        */
        
        return $data;
    }

    /**
     * Obtiene las variables disponibles para un cuadro específico
     * @param string $cuadro ID del cuadro
     * @return array|null
     */
    function efpa_get_variables_by_cuadro($cuadro) {
        $url = 'http://192.168.100.137:8081/simafir_api/ws/efpa/criterios/obtenerPorCuadro/' . urlencode($cuadro) . '?formato=json';
        
        $token = $this->efpa_get_token();
        
        if (!$token) {
            error_log('EFPA API Error: No se pudo obtener el token de autenticación para obtenerPorCuadro');
            return null;
        }
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Authorization: Bearer ' . $token
        ));
        
        $result = curl_exec($ch);
        
        if (curl_errno($ch)) {
            error_log('EFPA API Error (obtenerPorCuadro): ' . curl_error($ch));
            curl_close($ch);
            return null;
        }
        
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($http_code !== 200) {
            error_log('EFPA API HTTP Error: Code ' . $http_code . ' for obtenerPorCuadro. Cuadro: ' . $cuadro . '. Response: ' . $result);
            return null;
        }
        
        $data = json_decode($result, true);
        
        if (!is_array($data)) {
            error_log('EFPA API Error: obtenerPorCuadro no retornó un array válido para cuadro: ' . $cuadro . '. Response: ' . $result);
            return null;
        }
        
        return $data;
    }

    /**
     * Obtiene los datos de EFPA según los parámetros especificados
     * @param string $cuadro ID del cuadro
     * @param string $variable ID de la variable
     * @param string $pais Código del país
     * @param string $frecuencia Frecuencia (ANUAL, TRIMESTRAL, MENSUAL)
     * @param string $sector Sector
     * @param string $subsector Subsector
     * @param string $fechaInicio Fecha inicio (dd-mm-yyyy)
     * @param string $fechaFin Fecha fin (dd-mm-yyyy)
     * @return array|null
     */
    function efpa_get_data($cuadro, $variable, $pais, $frecuencia, $sector, $subsector, $fechaInicio, $fechaFin) {
        // Construir la URL con los parámetros
        $url = sprintf(
            'http://192.168.100.137:8081/simafir_api/ws/public/efpa/obtenerDatos/%s/%s/%s/%s/%s/%s?fechaInicio=%s&fechaFin=%s&formato=json',
            urlencode($cuadro),
            urlencode($variable),
            urlencode($pais),
            urlencode($frecuencia),
            urlencode($sector),
            urlencode($subsector),
            urlencode($fechaInicio),
            urlencode($fechaFin)
        );
        
        error_log('EFPA API Request URL (PUBLIC): ' . $url);
        
        // Este es un endpoint público, NO necesita token de autenticación
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60); // Timeout más largo para consultas complejas
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json'
            // No se envía Authorization header porque es público
        ));
        
        $result = curl_exec($ch);
        
        if (curl_errno($ch)) {
            $curl_error = curl_error($ch);
            error_log('EFPA API Error (obtenerDatos) - CURL ERROR: ' . $curl_error);
            error_log('EFPA API - URL que falló: ' . $url);
            curl_close($ch);
            return null;
        }
        
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        error_log('EFPA API Response - HTTP Code: ' . $http_code);
        error_log('EFPA API Response - Raw Response Length: ' . strlen($result) . ' bytes');
        error_log('EFPA API Response - First 500 chars: ' . substr($result, 0, 500));
        
        if ($http_code !== 200) {
            error_log('EFPA API HTTP Error: Code ' . $http_code . ' for URL: ' . $url);
            error_log('EFPA API Response Body: ' . $result);
            // Retornar el error HTTP con la respuesta del servidor
            return array(
                'error' => true,
                'mensaje' => $result,
                'tipo' => 'http_error',
                'http_code' => $http_code,
                'url' => $url
            );
        }
        
        $data = json_decode($result, true);
        $json_error = json_last_error();
        
        error_log('EFPA API Response - JSON decode result type: ' . gettype($data));
        error_log('EFPA API Response - Is array: ' . (is_array($data) ? 'YES' : 'NO'));
        error_log('EFPA API Response - JSON error code: ' . $json_error);
        
        if ($json_error !== JSON_ERROR_NONE) {
            error_log('EFPA API JSON Error: ' . json_last_error_msg());
            // Si no es JSON válido, retornar la respuesta cruda como string
            error_log('EFPA API - Returning raw response as it is not valid JSON');
            return array(
                'error' => true,
                'mensaje' => $result,
                'tipo' => 'raw_response'
            );
        }
        
        // Retornar lo que sea que devuelva el API (array, string, objeto)
        if (!is_array($data)) {
            error_log('EFPA API Response - Data type received: ' . gettype($data));
            error_log('EFPA API Response - Content: ' . print_r($data, true));
            // Envolver el mensaje en un array para mantener consistencia
            return array(
                'error' => true,
                'mensaje' => $data,
                'tipo' => 'non_array_response'
            );
        }
        
        error_log('EFPA API Success - Array count: ' . count($data));
        
        return $data;
    }

}
?>