AlkantarClanX12

Your IP : 216.73.217.24


Current Path : /www/capitalgmcbuickregina_830/public/wp-content/themes/lbx-egypt/app/
Upload File :
Current File : /www/capitalgmcbuickregina_830/public/wp-content/themes/lbx-egypt/app/helpers.php

<?php

use Illuminate\Support\Facades\Log;

/**
 * Theme helpers.
 * Theme helpers are in the global namespace for blade usage
 */

// namespace App;

// add_filter('acorn/throw_error_exception', function ($e) {
//     dd($e);
// }, 1, 999);



// Since we're using namespaces, the natual function names
// are no longer sufficient. Instead we need to use "App\\function_name".
// Since this is a pain, we'll use wrapper functions.
//
// These functions are called over the native functions, while in our namespace.
// To call a base function, you can override with \function_name.
//
// e.g. \add_action('init', 'App\function_name')
// function add_action($name, $callable, $priority = 10, $args = 1) {
//     return is_string($callable) && 0 !== strpos($callable, __NAMESPACE__)
//         ? \add_action($name, __NAMESPACE__."\\$callable", $priority, $args)
//         : \add_action($name, $callable, $priority, $args);
// }

if (!function_exists('add_actions')) {
  function add_actions($names, $callable, $priority = 10, $args = 1)
  {
    collect($names)->each(function ($name) use ($callable, $priority, $args) {
      add_action($name, $callable, $priority, $args);
    });
  }
}

if (!function_exists('add_filters')) {
  function add_filters($names, $callable, $priority = 10, $args = 1)
  {
    collect($names)->each(function ($name) use ($callable, $priority, $args) {
      add_filter($name, $callable, $priority, $args);
    });
  }
}

if (!function_exists('config')) {
  function config($string)
  {
    return \Roots\config($string);
  }
}

if (!function_exists('env')) {
  function env($string)
  {
    return \Roots\env($string);
  }
}

//THEME LOCALIZATION
load_theme_textdomain('leadbox', get_template_directory() . '/languages');

// Adding Leadbox Patterns
//Removing default patterns
remove_theme_support('core-block-patterns');

$lbSettings = get_leadbox_settings();
$showroom_page = get_page_by_title(ucfirst($lbSettings['manufacturer']) . " Showroom");
if ($showroom_page === null && $lbSettings['manufacturer']) {
  $sr_post = array(
    'post_title' => wp_strip_all_tags(ucfirst($lbSettings['manufacturer']) . " Showroom"),
    'post_content' => "<!-- wp:sage/showroom /-->",
    'post_status' => 'draft',
    'post_author' => 1,
    'post_category' => array(1),
    'post_type' => 'page'
  );
  // Insert the Showroom page into the database
  wp_insert_post($sr_post);

  // Create the Showroom Model page
  $sr_model_post = array(
    'post_title' => wp_strip_all_tags("Model"),
    'post_content' => "",
    'post_status' => 'publish',
    'post_author' => 1,
    'post_category' => array(1),
    'post_type' => 'page'
  );
  // Insert the Showroom Model page into the database
  wp_insert_post($sr_model_post);
  $showroom_model_page = get_page_by_title("Model");
  update_post_meta($showroom_model_page->ID, '_wp_page_template', 'template-showroom-model.blade.php');
}

//Including our patterns
//Adding Patterns Categories
add_action('current_screen', function ($screen) {
  if ( ! is_admin() || ! $screen ) return;

  $is_block_editor = method_exists($screen, 'is_block_editor') ? $screen->is_block_editor() : false;
  if ( ! $is_block_editor ) return;

  // Rutas locales en el TEMA PADRE
  $parent_dir = trailingslashit(get_template_directory());
  $cat_path   = $parent_dir . 'assets/patterns/categories-egypt.json';
  $pat_path   = $parent_dir . 'assets/patterns/patterns-egypt.json';

  // ----- Categorías
  $cats = get_transient('lb_patterns_categories_egypt');
  if ($cats === false) {
    if (function_exists('wp_json_file_decode') && file_exists($cat_path)) {
      $cats = wp_json_file_decode($cat_path, ['associative' => false]) ?: [];
    } else {
      $json_cat = @file_get_contents($cat_path);
      $cats = $json_cat ? json_decode($json_cat) : [];
    }
    set_transient('lb_patterns_categories_egypt', $cats, HOUR_IN_SECONDS * 12);
  }

  if (!empty($cats)) {
    foreach ($cats as $category) {
      if (!empty($category->name) && !empty($category->label)) {
        register_block_pattern_category(
          $category->name,
          ['label' => _x($category->label, 'Block pattern category', 'textdomain')]
        );
      }
    }
  }

  // ----- Patrones
  $patterns = get_transient('lb_patterns_list_egypt');
  if ($patterns === false) {
    if (function_exists('wp_json_file_decode') && file_exists($pat_path)) {
      $patterns = wp_json_file_decode($pat_path, ['associative' => false]) ?: [];
    } else {
      $json_pat = @file_get_contents($pat_path);
      $patterns = $json_pat ? json_decode($json_pat) : [];
    }
    set_transient('lb_patterns_list_egypt', $patterns, HOUR_IN_SECONDS * 12);
  }

  if (!empty($patterns)) {
    foreach ($patterns as $pattern) {
      if (empty($pattern->name) || empty($pattern->title) || empty($pattern->content) || empty($pattern->category)) {
        continue;
      }
      register_block_pattern(
        $pattern->name,
        [
          'title'       => __($pattern->title, 'textdomain'),
          'description' => _x($pattern->description ?? '', '', 'textdomain'),
          'content'     => str_replace("'", '"', $pattern->content),
          'categories'  => [$pattern->category],
        ]
      );
    }
  }
});

/* END PATTERNS */

// Global variable of the VDP data for Yoast and SEO functions
global $vdp_vehicle_data;
if (preg_match('[view|vue|form|forme]', $_SERVER["REQUEST_URI"])) {
  $vdp_url = explode("-", $_SERVER["REQUEST_URI"]);
  if (isset($_SERVER["QUERY_STRING"]) && strlen($_SERVER["QUERY_STRING"]) > 0) {
    $vdp_url[count($vdp_url) - 1] = str_replace("?" . $_SERVER["QUERY_STRING"], "", $vdp_url[count($vdp_url) - 1]);
  }
  $vdp_vehicle_data = get_vehicle_by_id(str_replace("/", "", $vdp_url[count($vdp_url) - 1]));
}

function get_dealer_hours_additional()
{
  return get_option('dealer-settings-hours-options');
}
function get_custom_finance_array()
{
  return get_option('dealer-settings-used-finance-custom-options');
}

function get_dealer_hours()
{
  $hours = get_option('dealer-settings-hours-options');
  $days = collect(['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']);
  $types = collect(['sale', 'service', 'parts', 'additionalone', 'additionaltwo', 'additionalthree']);

  if (isset($hours) && ($hours != false)) {
    return collect($hours)->groupBy(function ($_, $key) use ($types) {
      return $types->first(function ($v) use ($key) {
        return strpos($key, $v) === 0;
      });
    }, $preserve_keys = true)->map(function ($hours, $type) use ($days) {
      return $days->mapWithKeys(function ($day) use ($hours, $type) {
        $string = $hours->get("{$type}_hours_{$day}_closed", $default = false)
          ? 'Closed'
          : sprintf(
            "%s - %s",
            $hours->get("{$type}_hours_{$day}_start", ''),
            $hours->get("{$type}_hours_{$day}_end", '')
          );

        return [ucfirst($day) => $string];
      });
    });
  } else {
    $result["sale"] = array();
    $result["service"] = array();
    $result["parts"] = array();
    return $result;
  }
}

function get_dealer_contact()
{
  return get_option('dealer-settings-contact-options');
}

/**
 * Normaliza una coordenada (latitud/longitud) a un string decimal limpio, con
 * un máximo de 6 decimales y sin ceros sobrantes. Evita el artefacto de punto
 * flotante (p. ej. 45.33 -> 45.329999999999998) que aparece al castear a float
 * y serializar. Devuelve siempre string para que el JSON-LD sea estable en
 * cualquier configuración de `serialize_precision`.
 *
 * @param  mixed  $value
 * @return string Coordenada normalizada, o '' si no es numérica.
 */
function lbx_normalize_coordinate($value)
{
  $value = trim((string) $value);

  if ($value === '' || !is_numeric($value)) {
    return '';
  }

  // number_format redondea de forma decimal (no binaria) a 6 decimales.
  $formatted = number_format((float) $value, 6, '.', '');
  $formatted = rtrim($formatted, '0'); // quita ceros finales: 45.330000 -> 45.33
  $formatted = rtrim($formatted, '.'); // por si queda un punto suelto: 45. -> 45

  return $formatted;
}

/**
 * Serializa un array a JSON para un bloque <script type="application/ld+json">.
 * Fuerza serialize_precision=-1 durante la serialización para que los números
 * decimales (p. ej. coordenadas) usen su representación más corta y exacta, sin
 * el artefacto de punto flotante, sea cual sea la configuración del servidor.
 *
 * @param  mixed $data
 * @return string|false
 */
function lbx_json_ld($data)
{
  $previous = @ini_set('serialize_precision', '-1');

  $json = wp_json_encode(
    $data,
    JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_PRETTY_PRINT
  );

  if ($previous !== false) {
    @ini_set('serialize_precision', $previous);
  }

  return $json;
}

/**
 * Elimina recursivamente las propiedades vacías ('' o null) de un schema y
 * descarta los sub-objetos que quedan sin datos reales (solo con claves de
 * metadata como @type o unitText).
 *
 * @param  array $node
 * @return array
 */
function lbx_schema_prune(array $node)
{
  $meta = ['@context', '@type', 'unitText', 'priceCurrency'];

  foreach ($node as $key => $value) {
    if (is_array($value)) {
      $value = lbx_schema_prune($value);

      // Si solo sobreviven claves de metadata, el sub-objeto no aporta nada.
      if (empty(array_diff(array_keys($value), $meta))) {
        unset($node[$key]);
        continue;
      }

      $node[$key] = $value;
      continue;
    }

    if ($value === null || $value === '') {
      unset($node[$key]);
    }
  }

  return $node;
}

/**
 * Convierte los horarios de un departamento (día => "start - end" | "Closed")
 * en una lista de OpeningHoursSpecification. Los días cerrados o con rangos
 * no parseables se OMITEN: un día ausente se interpreta como cerrado y evita
 * la ambigüedad de un 00:00-00:00.
 *
 * @param  iterable|mixed $dayRanges Formato de get_dealer_hours()['sale'|'service'|'parts'].
 * @return array
 */
function lbx_opening_hours_schema($dayRanges)
{
  $specs = [];

  if (!is_iterable($dayRanges)) {
    return $specs;
  }

  foreach ($dayRanges as $day => $range) {
    $range = trim((string) $range);
    if ($range === '' || strtolower($range) === 'closed') {
      continue;
    }

    $parts = explode(' - ', $range);
    if (count($parts) !== 2) {
      continue;
    }

    $opens  = strtotime(trim($parts[0]));
    $closes = strtotime(trim($parts[1]));
    if ($opens === false || $closes === false) {
      continue;
    }

    $specs[] = [
      '@type'     => 'OpeningHoursSpecification',
      'dayOfWeek' => $day,
      'opens'     => date('H:i', $opens),
      'closes'    => date('H:i', $closes),
    ];
  }

  return $specs;
}

/**
 * Decide si el schema AutoDealer se emite en la página actual según el setting
 * "Schema Scope" (Dealer Settings → Contact → Schema):
 *  - '' | 'all' (default): todas las páginas — variante SD "Suggested" y
 *    comportamiento histórico del theme.
 *  - 'required': solo homepage + las páginas listadas en schema_required_pages
 *    (slugs separados por comas; vacío = about-us y service) — el mínimo que
 *    exige SD como "Required".
 *
 * @return bool
 */
function lbx_autodealer_schema_in_scope()
{
  $contact = get_dealer_contact();
  $contact = is_array($contact) ? $contact : [];

  if (trim((string) ($contact['schema_scope'] ?? '')) !== 'required') {
    return true;
  }

  if (is_front_page()) {
    return true;
  }

  $slugs = array_values(array_filter(array_map(
    'trim',
    explode(',', (string) ($contact['schema_required_pages'] ?? ''))
  )));
  if (empty($slugs)) {
    $slugs = ['about-us', 'service'];
  }

  return is_page($slugs);
}

/**
 * Construye el structured data AutoDealer + LocalBusiness del dealer para el
 * <head> global (LBT-1510, Shift Digital AI-Readiness A6).
 *
 * Autocontenido: lee Dealer Settings / Leadbox Settings directamente, sin
 * depender de variables inyectadas por composers a la vista. Devuelve el
 * array ya podado (sin propiedades vacías); si el site no tiene ni el nombre
 * del dealer configurado — o la página actual está fuera del Schema Scope
 * configurado — devuelve [] y no se emite nada.
 *
 * @return array
 */
function lbx_autodealer_schema()
{
  if (!lbx_autodealer_schema_in_scope()) {
    return [];
  }

  $contact  = get_dealer_contact();
  $contact  = is_array($contact) ? $contact : [];
  $branding = get_dealer_branding();
  $branding = is_array($branding) ? $branding : [];

  $dealerName = trim((string) ($contact['dealer_name'] ?? ''));
  $dealerUrl  = trim((string) ($contact['dealer_url'] ?? ''));

  // @id estable por entidad: el mismo IRI identifica al dealer en todas las
  // páginas del site (y permite referenciarlo desde otros schemas).
  $idBase = $dealerUrl !== '' ? $dealerUrl : home_url('/');
  if (!preg_match('#^https?://#i', $idBase)) {
    $idBase = 'https://' . ltrim($idBase, '/');
  }

  // Teléfonos por departamento: alimentan telephone (plano, para lectores
  // legacy) y contactPoint (con contactType, para entity matching).
  $phones = [
    'sales'   => trim((string) ($contact['sale_phone'] ?? '')),
    'service' => trim((string) ($contact['service_phone'] ?? '')),
    'parts'   => trim((string) ($contact['parts_phone'] ?? '')),
  ];

  $contactPoints = [];
  foreach ($phones as $department => $phone) {
    if ($phone === '') {
      continue;
    }
    $contactPoints[] = [
      '@type'       => 'ContactPoint',
      'contactType' => $department,
      'telephone'   => $phone,
    ];
  }

  // Marcas que vende el dealer: manufacturer principal + all_brands (lista
  // separada por comas). Ambos son texto libre en Leadbox Settings, así que
  // los valores todo-minúsculas se normalizan (acrónimos conocidos incluidos);
  // los que ya traen mayúsculas se respetan tal cual.
  $lbSettings = get_leadbox_settings();
  $lbSettings = is_array($lbSettings) ? $lbSettings : [];

  $acronyms = ['bmw' => 'BMW', 'gmc' => 'GMC', 'mini' => 'MINI', 'fiat' => 'FIAT', 'ram' => 'RAM'];
  $brands = [];
  $seenBrands = [];
  $brandNames = array_merge(
    [(string) ($lbSettings['manufacturer'] ?? '')],
    explode(',', (string) ($lbSettings['all_brands'] ?? ''))
  );
  foreach ($brandNames as $brandName) {
    $brandName = trim($brandName);
    $brandKey  = mb_strtolower($brandName);
    if ($brandName === '' || isset($seenBrands[$brandKey])) {
      continue;
    }
    $seenBrands[$brandKey] = true;
    if ($brandName === $brandKey) {
      $brandName = $acronyms[$brandKey] ?? ucwords($brandName);
    }
    $brands[] = [
      '@type' => 'Brand',
      'name'  => $brandName,
    ];
  }

  // sameAs: perfiles sociales de Dealer Settings → Social Media.
  $social = get_option('dealer-settings-socialmedia-options');
  $social = is_array($social) ? $social : [];
  $sameAs = [];
  foreach ($social as $key => $socialUrl) {
    if (substr((string) $key, -12) !== '_socialmedia') {
      continue;
    }
    $socialUrl = trim((string) $socialUrl);
    if ($socialUrl === '') {
      continue;
    }
    if (!preg_match('#^https?://#i', $socialUrl)) {
      $socialUrl = 'https://' . ltrim($socialUrl, '/');
    }
    // Descarta valores que no son URLs reales (p. ej. "FB" o "n/a"): el host
    // debe tener al menos un punto.
    $socialHost = parse_url($socialUrl, PHP_URL_HOST);
    if (!is_string($socialHost) || strpos($socialHost, '.') === false) {
      continue;
    }
    $sameAs[] = $socialUrl;
  }
  $sameAs = array_values(array_unique($sameAs));

  $hours        = get_dealer_hours();
  $saleHours    = lbx_opening_hours_schema($hours['sale'] ?? []);
  $serviceHours = lbx_opening_hours_schema($hours['service'] ?? []);
  $partsHours   = lbx_opening_hours_schema($hours['parts'] ?? []);

  // Departamentos como LocalBusiness anidados; solo se emiten si tienen
  // alguna señal real (teléfono u horarios propios).
  $departments = [];
  if ($phones['service'] !== '' || !empty($serviceHours)) {
    $departments[] = [
      '@type'                     => 'AutoRepair',
      'name'                      => trim($dealerName . ' Service'),
      'telephone'                 => $phones['service'],
      'openingHoursSpecification' => $serviceHours,
    ];
  }
  if ($phones['parts'] !== '' || !empty($partsHours)) {
    $departments[] = [
      '@type'                     => 'AutoPartsStore',
      'name'                      => trim($dealerName . ' Parts'),
      'telephone'                 => $phones['parts'],
      'openingHoursSpecification' => $partsHours,
    ];
  }

  $schema = [
    '@context'                  => 'http://schema.org',
    '@type'                     => ['AutoDealer', 'LocalBusiness'],
    '@id'                       => rtrim($idBase, '/') . '/#dealer',
    'name'                      => $dealerName,
    'url'                       => $dealerUrl,
    'logo'                      => $branding['logo_image'] ?? '',
    'image'                     => $branding['logo_image'] ?? '',
    'telephone'                 => array_values(array_unique(array_filter($phones))),
    'contactPoint'              => $contactPoints,
    'brand'                     => $brands,
    'sameAs'                    => $sameAs,
    'currenciesAccepted'        => ['CAD'],
    'openingHoursSpecification' => $saleHours,
    'department'                => $departments,
    'address'                   => [
      '@type'           => 'PostalAddress',
      'addressLocality' => $contact['address_city'] ?? '',
      'addressRegion'   => $contact['address_province'] ?? '',
      'postalCode'      => $contact['address_postal_code'] ?? '',
      'streetAddress'   => $contact['address_line_1'] ?? '',
    ],
  ];

  // Geo: solo si latitude y longitude son numéricas (Dealer Settings →
  // Contact → Address). Coordenadas malas son peores que no tener geo.
  $lat = isset($contact['latitude'])  ? trim((string) $contact['latitude'])  : '';
  $lng = isset($contact['longitude']) ? trim((string) $contact['longitude']) : '';
  if (is_numeric($lat) && is_numeric($lng)) {
    $schema['geo'] = [
      '@type'     => 'GeoCoordinates',
      'latitude'  => (float) lbx_normalize_coordinate($lat),
      'longitude' => (float) lbx_normalize_coordinate($lng),
    ];
  }

  $schema = lbx_schema_prune($schema);

  // Sin nombre no hay entidad que declarar: mejor no emitir nada.
  if (!isset($schema['name'])) {
    return [];
  }

  return $schema;
}

/**
 * Mapea un drivetrain de inventario (AWD, 4WD, FWD…) a su valor canónico de
 * DriveWheelConfigurationValue; si no matchea ninguno devuelve el texto tal
 * cual (schema.org acepta texto libre).
 *
 * @param  mixed  $drivetrain
 * @return string
 */
function lbx_drivewheel_configuration($drivetrain)
{
  $drivetrain = trim((string) $drivetrain);
  $driveMap = [
    'AWD' => 'https://schema.org/AllWheelDriveConfiguration',
    '4WD' => 'https://schema.org/FourWheelDriveConfiguration',
    '4X4' => 'https://schema.org/FourWheelDriveConfiguration',
    'FWD' => 'https://schema.org/FrontWheelDriveConfiguration',
    'RWD' => 'https://schema.org/RearWheelDriveConfiguration',
  ];
  $driveKey = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $drivetrain));

  return $driveMap[$driveKey] ?? $drivetrain;
}

/**
 * URL absoluta del VDP de un vehículo, replicando el slug que construye la
 * vehicle card (spa-vehicle-card.vue.js → viewSlug):
 * /view/{condition}-{year}-{make}-{model}[-{vin}]-{id}/ (/vue/ en francés).
 * El flag use-slug-vin sale del genius config, igual que en la card.
 *
 * @param  array  $vehicle Item del array `vehicles` de inventory.json.
 * @return string
 */
function lbx_vehicle_vdp_url(array $vehicle)
{
  $slugify = static function ($value) {
    return str_replace(' ', '-', strtolower(trim((string) $value)));
  };

  // El JS solo elimina la PRIMERA '/' del modelo (String.replace sin flag global).
  $model = $slugify($vehicle['model'] ?? '');
  $slashPos = strpos($model, '/');
  if ($slashPos !== false) {
    $model = substr_replace($model, '', $slashPos, 1);
  }

  $parts = [
    $slugify($vehicle['condition'] ?? ''),
    $slugify($vehicle['year'] ?? ''),
    $slugify($vehicle['make'] ?? ''),
    $model,
  ];

  $useVin = (defined('GENIUS') && isset(GENIUS['vehicle-card']['data']['use-slug-vin']))
    ? GENIUS['vehicle-card']['data']['use-slug-vin']
    : false;
  if ($useVin && !empty($vehicle['vin'])) {
    $parts[] = (string) $vehicle['vin'];
  }

  $parts[] = (string) ($vehicle['id'] ?? '');

  $base = (function_exists('isFrench') && isFrench()) ? '/vue/' : '/view/';

  return home_url($base . implode('-', $parts) . '/');
}

/**
 * Construye el ItemList de Car (schema.org) de una vista de inventario
 * (SRP/VLP) a partir de los vehículos YA filtrados/ordenados/paginados que la
 * vista renderiza (LBT-1508, Shift Digital AI-Readiness A4).
 *
 * Solo emite en vistas de inventario reales: los bloques con `filter` activo.
 * Los carousels (home, etc.) usan el mismo bloque con filter=false y se
 * omiten. La lista se acota a la primera "página" visible del SRP
 * (vehiclePerPage o loadMoreBtnItemsPerPage del genius config, fallback 24)
 * para que el JSON-LD refleje lo que el usuario ve sin inflar el HTML.
 *
 * @param  array $vehicles Vehículos de la vista (post filter/sort/paginate).
 * @param  array $options  Opciones del bloque inventory-block.
 * @return array
 */
function lbx_srp_itemlist_schema(array $vehicles, array $options = [])
{
  if (!filter_var($options['filter'] ?? false, FILTER_VALIDATE_BOOLEAN)) {
    return [];
  }

  if (empty($vehicles)) {
    return [];
  }

  $cap = 24;
  if (defined('GENIUS') && isset(GENIUS['srp-layout']['data']) && is_array(GENIUS['srp-layout']['data'])) {
    $layoutData = GENIUS['srp-layout']['data'];
    if (!empty($layoutData['vehiclePerPage'])) {
      $cap = (int) $layoutData['vehiclePerPage'];
    } elseif (!empty($layoutData['loadMoreBtnItemsPerPage'])) {
      $cap = (int) $layoutData['loadMoreBtnItemsPerPage'];
    }
  }
  $vehicles = array_slice(array_values($vehicles), 0, max(1, $cap));

  $items = [];
  foreach ($vehicles as $vehicle) {
    if (!is_array($vehicle)) {
      continue;
    }

    $condition = trim((string) ($vehicle['condition'] ?? ''));
    $isNew = strtolower($condition) === 'new';
    $url = lbx_vehicle_vdp_url($vehicle);

    $offer = [
      '@type'         => 'Offer',
      'availability'  => !empty($vehicle['incoming']) ? 'https://schema.org/OutOfStock' : 'https://schema.org/InStock',
      'priceCurrency' => 'CAD',
      'url'           => $url,
    ];
    $price = $vehicle['price'] ?? null;
    if (is_numeric($price) && (float) $price > 0) {
      $offer['price'] = (string) $price;
    }

    $car = [
      '@type'                       => 'Car',
      'name'                        => trim(preg_replace('/\s+/', ' ', sprintf(
        '%s %s %s %s %s',
        $condition,
        $vehicle['year'] ?? '',
        $vehicle['make'] ?? '',
        $vehicle['model'] ?? '',
        $vehicle['trim'] ?? ''
      ))),
      'url'                         => $url,
      'image'                       => (string) ($vehicle['picture'] ?? ''),
      'brand'                       => [
        '@type' => 'Brand',
        'name'  => (string) ($vehicle['make'] ?? ''),
      ],
      'model'                       => (string) ($vehicle['model'] ?? ''),
      'vehicleModelDate'            => (string) ($vehicle['year'] ?? ''),
      'itemCondition'               => $isNew
        ? 'https://schema.org/NewCondition'
        : 'https://schema.org/UsedCondition',
      'driveWheelConfiguration'     => lbx_drivewheel_configuration($vehicle['drivetrain'] ?? ''),
      'vehicleIdentificationNumber' => (string) ($vehicle['vin'] ?? ''),
      'sku'                         => (string) ($vehicle['stocknumber'] ?? ''),
      'offers'                      => $offer,
    ];

    // Kilometraje: en usados y demos (mismo criterio que las cards).
    if ((!$isNew || !empty($vehicle['demo'])) && is_numeric($vehicle['mileage'] ?? null)) {
      $car['mileageFromOdometer'] = [
        '@type'    => 'QuantitativeValue',
        'value'    => (string) $vehicle['mileage'],
        'unitText' => 'KM',
      ];
    }

    $items[] = [
      '@type'    => 'ListItem',
      'position' => count($items) + 1,
      'item'     => $car,
    ];
  }

  if (empty($items)) {
    return [];
  }

  $schema = [
    '@context'        => 'http://schema.org',
    '@type'           => 'ItemList',
    'name'            => wp_strip_all_tags((string) get_the_title()),
    'numberOfItems'   => count($items),
    'itemListElement' => $items,
  ];

  return lbx_schema_prune($schema);
}

/**
 * Renderiza el <script> JSON-LD del ItemList del SRP, o '' si la vista no
 * aplica (bloque sin filtro activo o sin vehículos). Pensado para llamarse
 * desde layouts/srp-layout/* justo después de paginar.
 *
 * @param  mixed $vehicles Vehículos ya filtrados/paginados de la vista.
 * @param  mixed $options  Opciones del bloque inventory-block.
 * @return string
 */
function lbx_render_srp_itemlist_schema($vehicles, $options = [])
{
  if (!is_array($vehicles)) {
    return '';
  }

  $schema = lbx_srp_itemlist_schema($vehicles, is_array($options) ? $options : []);
  if (empty($schema)) {
    return '';
  }

  return "\n<script type=\"application/ld+json\">\n" . lbx_json_ld($schema) . "\n</script>\n";
}

/**
 * Construye el structured data Car (schema.org) de un vehículo para las
 * plantillas VDP/product/form y lo devuelve ya serializado como JSON-LD.
 *
 * Reemplaza los bloques JSON armados a mano en los blades: al construir el
 * schema como array PHP y serializarlo con lbx_json_ld(), la salida es JSON
 * válido por construcción, incluso con descripciones multi-párrafo (saltos de
 * línea, comillas, HTML). La descripción se emite como texto plano y las
 * propiedades opcionales sin valor se omiten en vez de emitirse como cadenas
 * vacías (p. ej. nunca se emite "price": "" en vehículos sin precio).
 *
 * @param array      $data     JSON per-vehicle (uploads/data/<id>.json).
 * @param array|null $contact  Datos de contacto del dealer.
 * @param array|null $branding Branding del dealer (logo).
 * @param array      $args     Overrides por plantilla: name, image, url, mileage.
 * @return string|false
 */
function lbx_vehicle_car_schema($data, $contact = null, $branding = null, $args = [])
{
  $data     = is_array($data) ? $data : [];
  $contact  = is_array($contact) ? $contact : [];
  $branding = is_array($branding) ? $branding : [];

  // Descripción: texto plano, sin HTML, sin saltos de línea y acotada.
  $description = (string) ($data['description'] ?? '');
  if ($description !== '') {
    $description = wp_strip_all_tags($description);
    $description = html_entity_decode($description, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    $description = str_replace("\xC2\xA0", ' ', $description); // nbsp
    $description = trim(preg_replace('/\s+/u', ' ', $description));

    if (mb_strlen($description) > 5000) {
      $description = mb_substr($description, 0, 5000);
      $cut = mb_strrpos($description, ' ');
      if ($cut !== false && $cut > 4000) {
        $description = mb_substr($description, 0, $cut);
      }
      $description .= '…';
    }
  }

  // drivetrain -> valor canónico de DriveWheelConfigurationValue (o el texto
  // tal cual si no matchea ninguno).
  $driveWheelConfiguration = lbx_drivewheel_configuration($data['drivetrain'] ?? '');

  $offer = [
    '@type'         => 'Offer',
    'availability'  => !empty($data['incoming']) ? 'https://schema.org/OutOfStock' : 'https://schema.org/InStock',
    'priceCurrency' => 'CAD',
    'url'           => (string) ($args['url'] ?? ''),
    'seller'        => [
      '@type'     => 'AutoDealer',
      'name'      => (string) ($contact['dealer_name'] ?? ''),
      'telephone' => (string) ($contact['sale_phone'] ?? ''),
      'image'     => (string) ($branding['logo_image'] ?? ''),
      'address'   => [
        '@type'           => 'PostalAddress',
        'addressLocality' => (string) ($contact['address_city'] ?? ''),
        'addressRegion'   => (string) ($contact['address_province'] ?? ''),
        'postalCode'      => (string) ($contact['address_postal_code'] ?? ''),
        'streetAddress'   => (string) ($contact['address_line_1'] ?? ''),
      ],
    ],
  ];

  $price = $data['price'] ?? null;
  if (is_numeric($price) && (float) $price > 0) {
    $offer['price'] = (string) $price;
  }

  // seats/doors en 0 son data ausente, no un valor real: se omiten.
  $seats = $data['seats'] ?? null;
  $seats = (is_numeric($seats) && (int) $seats > 0) ? (string) $seats : '';
  $doors = $data['doors'] ?? null;
  $doors = (is_numeric($doors) && (int) $doors > 0) ? (string) $doors : '';

  $schema = [
    '@context'                    => 'http://schema.org',
    '@type'                       => 'Car',
    'name'                        => (string) ($args['name'] ?? ''),
    'image'                       => (string) ($args['image'] ?? ''),
    'itemCondition'               => strtolower((string) ($data['condition'] ?? '')) == 'new'
      ? 'http://schema.org/NewCondition'
      : 'http://schema.org/UsedCondition',
    'manufacturer'                => (string) ($data['make'] ?? ''),
    'vehicleIdentificationNumber' => (string) ($data['vin'] ?? ''),
    'vehicleModelDate'            => (string) ($data['year'] ?? ''),
    'brand'                       => (string) ($data['make'] ?? ''),
    'model'                       => (string) ($data['model'] ?? ''),
    'description'                 => $description,
    'vehicleInteriorColor'        => (string) ($data['interiorcolor'] ?? ''),
    'bodyType'                    => (string) ($data['bodystyle'] ?? ''),
    'vehicleSeatingCapacity'      => $seats,
    'mileageFromOdometer'         => [
      '@type'    => 'QuantitativeValue',
      'value'    => (string) ($args['mileage'] ?? ($data['mileage'] ?? '')),
      'unitText' => 'KM',
    ],
    'numberOfDoors'               => $doors,
    'vehicleEngine'               => [
      '@type'    => 'EngineSpecification',
      'name'     => (string) ($data['engine'] ?? ''),
      'fuelType' => (string) ($data['fueltype'] ?? ''),
    ],
    'driveWheelConfiguration'     => $driveWheelConfiguration,
    'vehicleTransmission'         => (string) ($data['transmission'] ?? ''),
    'color'                       => (string) ($data['exteriorcolor'] ?? ''),
    'sku'                         => (string) ($data['stocknumber'] ?? ''),
    'offers'                      => $offer,
  ];

  return lbx_json_ld(lbx_schema_prune($schema));
}

/**
 * ¿La página que se está mostrando es una página de Preguntas Frecuentes?
 *
 * Se considera FAQ si usa la plantilla template-faq.blade.php o si su slug
 * contiene "faq" (cubre rutas como /faq/ o /finance/credit-faq/ aunque no
 * usen la plantilla dedicada).
 *
 * @return bool
 */
function lbx_is_faq_page()
{
  if (!function_exists('is_page') || !is_page()) {
    return false;
  }

  if (get_page_template_slug() === 'template-faq.blade.php') {
    return true;
  }

  $queried = get_queried_object();

  return ($queried instanceof WP_Post)
    && stripos((string) $queried->post_name, 'faq') !== false;
}

/**
 * Imprime el structured data FAQPage (schema.org) en el <head> de las páginas
 * de Preguntas Frecuentes.
 *
 * Lee el contenido ya publicado de la página y deriva los pares pregunta/
 * respuesta con lbx_build_faq_entities(). Solo emite el bloque JSON-LD si se
 * detectan al menos dos pares, de modo que nunca se imprime un schema vacío o
 * incompleto. Reutiliza lbx_json_ld() para la serialización.
 *
 * Si un plugin SEO (p. ej. Yoast) ya genera el FAQPage desde su propio bloque
 * de FAQ, se aborta para no duplicar el structured data.
 *
 * @return void
 */
function lbx_render_faqpage_schema()
{
  if (!lbx_is_faq_page()) {
    return;
  }

  $post = get_queried_object();
  if (!($post instanceof WP_Post) || trim((string) $post->post_content) === '') {
    return;
  }

  $html = apply_filters('the_content', $post->post_content);

  // Si un plugin SEO (p. ej. Yoast) ya genera el FAQPage desde su propio bloque
  // de FAQ, no duplicamos el structured data.
  if (
    stripos($html, 'schema-faq-question') !== false
    || stripos($html, 'wp-block-yoast-faq-block') !== false
  ) {
    return;
  }

  $entities = lbx_build_faq_entities($html);

  if (count($entities) < 2) {
    return;
  }

  $schema = [
    '@context'   => 'https://schema.org',
    '@type'      => 'FAQPage',
    'mainEntity' => $entities,
  ];

  echo "\n  <script type=\"application/ld+json\">\n"
    . lbx_json_ld($schema)
    . "\n  </script>\n";
}

/**
 * Extrae los pares pregunta/respuesta de un fragmento HTML para construir el
 * mainEntity de un FAQPage schema.
 *
 * La heurística es tolerante a los distintos formatos que usan los sitios:
 *  - Pregunta: un encabezado <h2>–<h6>, o un <p> cuyo contenido sea íntegramente
 *    negrita (<strong>/<b>), siempre que el texto termine en "?".
 *  - Respuesta: el texto de los párrafos siguientes hasta la próxima pregunta.
 *  - Un encabezado que no termina en "?" se trata como título de sección y cierra
 *    la respuesta en curso.
 *  - Se elimina el prefijo "Q:" / "A:" que anteponen algunos sitios.
 *
 * Las respuestas se guardan como texto plano (válido para schema.org), por lo que
 * no se conserva el HTML interno (listas, enlaces) de la respuesta.
 *
 * @param  string $html
 * @return array  Lista de nodos Question; vacío si no se detecta ninguno.
 */
function lbx_build_faq_entities($html)
{
  $html = trim((string) $html);
  if ($html === '' || !class_exists('DOMDocument')) {
    return [];
  }

  $dom      = new DOMDocument();
  $previous = libxml_use_internal_errors(true);
  $dom->loadHTML('<?xml encoding="utf-8" ?><div id="lbx-faq-root">' . $html . '</div>');
  libxml_clear_errors();
  libxml_use_internal_errors($previous);

  $xpath = new DOMXPath($dom);
  $root  = $xpath->query('//div[@id="lbx-faq-root"]')->item(0);
  if (!$root) {
    return [];
  }

  // Encabezados y párrafos en orden de documento (atravesando los contenedores
  // que generan los bloques de Gutenberg).
  $nodes = $xpath->query('.//h2|.//h3|.//h4|.//h5|.//h6|.//p', $root);

  $entities = [];
  $current  = null;

  foreach ($nodes as $node) {
    $question = lbx_faq_extract_question($node);

    if ($question !== null) {
      $entities[] = [
        '@type'          => 'Question',
        'name'           => $question,
        'acceptedAnswer' => ['@type' => 'Answer', 'text' => ''],
      ];
      $current = count($entities) - 1;
      continue;
    }

    // Encabezado que no es pregunta: separador de sección.
    if (strtolower($node->nodeName)[0] === 'h') {
      $current = null;
      continue;
    }

    if ($current !== null) {
      $text = lbx_faq_clean_text($node->textContent, true);
      if ($text !== '') {
        $existing = $entities[$current]['acceptedAnswer']['text'];
        $entities[$current]['acceptedAnswer']['text'] =
          $existing === '' ? $text : $existing . ' ' . $text;
      }
    }
  }

  // Descarta preguntas que se quedaron sin respuesta.
  return array_values(array_filter($entities, function ($q) {
    return $q['acceptedAnswer']['text'] !== '';
  }));
}

/**
 * Devuelve el texto de la pregunta si $node es un nodo pregunta, o null si no.
 *
 * Es pregunta un encabezado <h2>–<h6> o un <p> cuyo contenido sea íntegramente
 * negrita, siempre que el texto (ya sin el prefijo "Q:") termine en "?".
 *
 * @param  DOMElement $node
 * @return string|null
 */
function lbx_faq_extract_question(DOMElement $node)
{
  $tag  = strtolower($node->nodeName);
  $text = lbx_faq_clean_text($node->textContent, false);

  if ($text === '' || substr($text, -1) !== '?') {
    return null;
  }

  if (in_array($tag, ['h2', 'h3', 'h4', 'h5', 'h6'], true)) {
    return $text;
  }

  if ($tag !== 'p') {
    return null;
  }

  // <p> que solo contiene negrita (y, a lo sumo, saltos de línea) => pregunta.
  $hasBold = false;
  foreach ($node->childNodes as $child) {
    if ($child->nodeType === XML_TEXT_NODE) {
      if (trim($child->textContent) !== '') {
        return null;
      }
    } elseif ($child->nodeType === XML_ELEMENT_NODE) {
      $childTag = strtolower($child->nodeName);
      if (in_array($childTag, ['strong', 'b'], true)) {
        $hasBold = true;
      } elseif ($childTag !== 'br') {
        return null;
      }
    }
  }

  return $hasBold ? $text : null;
}

/**
 * Normaliza el texto de un nodo: colapsa los espacios en blanco, decodifica las
 * entidades y elimina el prefijo "Q:" o "A:" que anteponen algunos sitios.
 *
 * @param  string $raw
 * @param  bool   $isAnswer  Si es respuesta quita el prefijo "A:"; si no, "Q:".
 * @return string
 */
function lbx_faq_clean_text($raw, $isAnswer = false)
{
  $text = html_entity_decode((string) $raw, ENT_QUOTES | ENT_HTML5, 'UTF-8');
  $text = preg_replace('/\s+/u', ' ', $text);
  $text = trim($text);

  $prefix = $isAnswer ? 'A' : 'Q';
  $text   = preg_replace('/^' . $prefix . '\s*:\s*/u', '', $text);

  return trim($text);
}

function get_iboost_option()
{
  $option = "disabled";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["iboost"])
    && !empty($lbSettings["iboost"]) && (strlen($lbSettings["iboost"]) > 0)
  ) {
    $option = strtolower($lbSettings["iboost"]);
  }

  return $option;
}

function get_dealer_iboost()
{
  $dealer_input = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["iboost_token"])
    && !empty($lbSettings["iboost_token"]) && (strlen($lbSettings["iboost_token"]) > 0)
  ) {
    $dealer_input = $lbSettings["iboost_token"];
  }

  return $dealer_input;
}

function get_dealer_policies()
{
  return get_option('dealer-settings-policies-options');
}

function get_dealer_labels()
{
  return get_option('dealer-settings-labels-options');
}
function get_dealer_listings()
{
  return get_option('dealer-settings-listing-options');
}

function get_dealer_branding()
{
  return get_option('dealer-settings-branding-options');
}

function get_dealer_disclaimer()
{
  return get_option('dealer-settings-disclaimer-options');
}

function get_dealer_filter()
{
  return get_option('dealer-settings-filter-options');
}

function get_newsletter_status()
{
  return get_option('dealer-settings-branding-options')['newsletter_enabled_option'];
}

function is_my_garage_active()
{
  $options = get_option('dealer-settings-my-garage-options', []);
  $my_garage_status = is_array($options) && isset($options['my_garage_status'])
      ? $options['my_garage_status']
      : '';

  $my_garage_is_active = LBX_is_plugin_activated('Leadbox Saved Vehicles');

  return (strtolower($my_garage_status) === 'enabled' && $my_garage_is_active);
}

function format_phone($data)
{
  if (preg_match('/^\+\d(\d{3})(\d{3})(\d{4})$/', $data, $matches)) {
    $result = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
    return $result;
  }
}

function format_phone_v2($data)
{
  if (preg_match('/^\+\d(\d{3})(\d{3})(\d{4})$/', $data, $matches)) {
    $result = '(' . $matches[1] . ') ' . $matches[2] . '-' . $matches[3];
    return $result;
  }
}

function change_image($image)
{
  $vdp_str = get_query_var('vdp_string');
  $vdp_arr = explode('-', $vdp_str);
  $id = array_pop($vdp_arr);

  $data = $GLOBALS['vdp_vehicle_data'];

  $id_feature_image = get_queried_object_id();
  $branding = get_dealer_branding();
  if (isset($data['pictures'])) {
    $file = $data['pictures'][0];
  }

  if (has_post_thumbnail($id_feature_image)) {
    return wp_get_attachment_image_src(get_post_thumbnail_id($id_feature_image), 'full')[0];
  } else {
    if (isset($id) && $id > 0) {
      if (isset($data['pictures']) && url_exists($file)) {

        $image = $data['pictures'][0];
        if (strpos($image, '?ts=') !== false) {
          $expStr = explode("?ts=", $image);
          if (count($expStr) > 0) {
            if (str_contains($expStr[0], "http")) {
              if (str_contains($expStr[0], "-XXL"))
                $image = str_replace("-XXL", "-large.jpg", $expStr[0]);
              else
                $image = $expStr[0] . '-large.jpg';
            } else {
              if (str_contains($expStr[0], "-XXL"))
                $image = 'https:' . str_replace("-XXL", "-large.jpg", $expStr[0]);
              else
                $image = 'https:' . $expStr[0] . '-large.jpg';
            }
          }
          return str_replace("http:", "https:", $image);

        } else {
          if (str_contains($image, "-XXL"))
            return str_replace("-XXL", "-large.jpg", str_replace("http:", "https:", $image));
          else
            return str_replace("http:", "https:", $image) . '-large.jpg';

        }
      } else {
        return $branding['logo_image'];
      }
    } else {
      return $branding['logo_image'];
    }
  }
}

function getFilesInFolder($folder, $extension)
{
  $target = realpath(get_template_directory() . $folder);
  dd($folder, $target);

  if (!$target) {
    return array();
  } else {
    $files = scandir($target);

    return array_filter($files, function ($file) use ($extension) {
      if (in_array($file, ['.', '..'])) {
        return array();
      }
      return ends_with($file, $extension);
    });
  }

}

function getFormLocale_text()
{
  $idiom = get_locale();
  $view = 'forme';
  if (strpos($idiom, 'en') !== false) {
    $view = 'form';
  }
  return $view;
}

function getDetailLocale_text()
{
  $idiom = get_locale();
  $view = 'vue';
  if (strpos($idiom, 'en') !== false) {
    $view = 'view';
  }
  return $view;
}

function verifyRebateToTranslate($rebate)
{
  $idiom = get_locale();

  if (strpos($idiom, 'en') !== false) {
    return $rebate;
  }

  if (strpos(strtolower($rebate), 'delivery allowance') !== false) {
    return 'Rabais à la livraison';
  }

  if (strpos(strtolower($rebate), 'ev rebate retail') !== false) {
    return 'Rabais gouvernement VE';
  }

  return $rebate;
}

function getInventoryLocale_text()
{
  $idiom = get_locale();
  $view = 'inventaire-neufs';
  if (strpos($idiom, 'en') !== false) {
    $view = 'new-inventory';
  }
  return $view;
}

function getFormPageLocale($form)
{

  $textForm = getFormLocale_name($form);
  return '/' . getFormLocale_text() . '/' . $textForm;
}

function modelTotal($regex, $trim = false, $model = '')
{
  $inventory = get_search_inventory();

  $total = 0;
  $matches = [];

  if(strtolower($model) == 'escapeplug-inhybrid'){
      foreach ($inventory as $vehicle) {
        if (isset($vehicle) && isset($vehicle["condition"]) && strtolower($vehicle["condition"]) == 'new') {
          if (strtolower("escape") == strtolower($vehicle['model']) && (strtolower($vehicle['trim']) == 'plug-in hybrid' || strtolower($vehicle['trim']) == 'phev')){
            $regex = '/(plug-inhybrid|phev)/';
            preg_match($regex, strtolower($vehicle['trim']), $matches);
            if (isset($matches) && count($matches) > 0) {
              $total++;
            }
          }
        }
      }
    }
    else {
      if ($trim) {
        foreach ($inventory as $vehicle) {
          if (isset($vehicle) && isset($vehicle["condition"]) && strtolower($vehicle["condition"]) == 'new') {
            if (strtolower($model) == strtolower($vehicle['model'])) {
              preg_match($regex, strtolower($vehicle['trim']), $matches);
              if (isset($matches) && count($matches) > 0) {
                $total++;
              }
            }
          }
        }
      } else {
        if(strtolower($model) == 'transit'){
          $regex = '/transit (cargo van|cutaway)[a-zA-Z ]*/';
         }
        else if(strtolower($model) == 'superduty'){
          $regex = '/super duty [a-zA-Z ]*/';
        }
        foreach ($inventory as $vehicle) {
          if (isset($vehicle) && isset($vehicle["condition"]) && strtolower($vehicle["condition"]) == 'new') {
            preg_match($regex, strtolower($vehicle['model']), $matches);
            if (isset($matches) && count($matches) > 0) {
              $total++;
            }
          }
        }
      }
    }



  return $total;
}

function modelPrice($regex, $istrim = false)
{
  $inventory = get_search_inventory();

  $price = 0;
  $matches = [];

  foreach ($inventory as $vehicle) {
    if (($vehicle["price"] > 0 && $vehicle["price"] < $price) || $price == 0) {
      if (isset($vehicle) && isset($vehicle["condition"]) && strtolower($vehicle["condition"]) == 'new') {
        if (!$istrim) {
          preg_match($regex, strtolower(str_replace(' ', '-', $vehicle['model'])), $matches);
          if (isset($matches) && count($matches) > 0) {
            $price = $vehicle["price"];
          }
        } else {

          preg_match($regex, strtolower(str_replace(' ', '-', $vehicle['model'])) . '' . strtolower(str_replace(' ', '-', $vehicle['trim'])), $matches);
          if (isset($matches) && count($matches) > 0) {
            $price = $vehicle["price"];
          }
        }
      }
    }
  }

  return currency_format($price);
}

function currency_format_decimals($n,$d)
{
    $lang = get_locale();
    if ($lang == 'fr_CA')
        return (number_format(floatval($n), $d, ',', ' ')) . ' $';
    else
        return "$" . (number_format(floatval($n), $d));
}

function getFormLocale_name($name)
{
  $idiom = get_locale();
  switch ($name) {
    case 'contact-us':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'contactez-nous';
      }
      break;
    case 'request-more-information':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'demande-d-informations';
      }
      break;
    case 'book-a-test-drive':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'reservez-un-essai-routier';
      }
      break;
    case 'trade-in-appraisal':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'evaluation-du-vehicule-dechange';
      }
      break;
    case 'confirm-availability':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'confirmez-la-disponibilite';
      }
      break;
    case 'book-a-service-appointment':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'prenez-rendez-vous';
      }
      break;
    case 'schedule-viewing':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'planifier-un-rendez-vous';
      }
      break;
    case 'model-test-drive':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'essai-de-modele';
      }
      break;
    case 'model-trade-in':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'modele-reprise';
      }
      break;
    case 'model-reserve-now':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'modele-reservez-maintenant';
      }
      break;
    case 'model-confirm-availability':
      if (strpos($idiom, 'en') !== false) {
          return $name;
      } else {
          return 'modele-confirmer-la-disponibilite';
      }
      break;
    case 'get-offer-information':
      if (strpos($idiom, 'en') !== false) {
        return $name;
      } else {
        return 'obtenir-des-informations-sur-l-offre';
      }
      break;
    default:
      return $name;
      break;
  }
}

function isFrench()
{
  return false !== strpos(get_locale(), 'fr');
}

function outerLabelOmnisearch($outerLabel)
{
  if (isset($outerLabel)) {
    echo ($outerLabel);
  } else {
    _e('Search', 'leadbox');
  }
}
function innerLabelOmnisearch($innerLabel)
{
  if (isset($innerLabel)) {
    echo ($innerLabel);
  } else {
    _e('Search by Type, Year, Make, Model or Stock #', 'leadbox');
  }
}

function getVehiclesYearUsed($yearVehicle)
{
  $year = date('Y');
  $totalYear = $year - $yearVehicle;
  return $totalYear;
}

function get_leadbox_settings()
{
  return get_option('leadbox-settings');
}

function get_leadbox_finance_settings()
{
  return get_option('dealer-settings-branding-options');
}

function get_leadbox_used_finance_settings()
{
  return get_option('dealer-settings-used-finance-options');
}

function has_dealer_listings() {
  if (function_exists('get_dealer_listings')) {
    if (
      (!empty(get_listing_image_new())) ||
      (!empty(get_listing_image_new_fr())) ||
      (!empty(get_listing_image_used())) ||
      (!empty(get_listing_image_used_fr()))
    ) {
        return true;
    }
  }
  return false;
}


function get_listing_image_new()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["image_new"])
    && !empty($listingSettings["image_new"]) && (strlen($listingSettings["image_new"]) > 0)
  ) {
    $dealer_input = $listingSettings["image_new"];
  }

  return $dealer_input;
}
//get listing link new
function get_listing_link_new()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["link_new"])
    && !empty($listingSettings["link_new"]) && (strlen($listingSettings["link_new"]) > 0)
  ) {
    $dealer_input = $listingSettings["link_new"];
  }

  return $dealer_input;
}

//get linsting image new fr
function get_listing_image_new_fr()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["image_new_fr"])
    && !empty($listingSettings["image_new_fr"]) && (strlen($listingSettings["image_new_fr"]) > 0)
  ) {
    $dealer_input = $listingSettings["image_new_fr"];
  }

  return $dealer_input;
}

//get listing link new fr
function get_listing_link_new_fr()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["link_new_fr"])
    && !empty($listingSettings["link_new_fr"]) && (strlen($listingSettings["link_new_fr"]) > 0)
  ) {
    $dealer_input = $listingSettings["link_new_fr"];
  }

  return $dealer_input;
}

//get insert after new
function get_insert_after_new()
{
  $dealer_input = 0;
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["insert_after_new"])
    && !empty($listingSettings["insert_after_new"]) && (strlen($listingSettings["insert_after_new"]) > 0)
  ) {
    $dealer_input = $listingSettings["insert_after_new"];
  }

  return $dealer_input;
}

//get limit date new
function get_limit_date_new()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["limit_date_new"])
    && !empty($listingSettings["limit_date_new"]) && (strlen($listingSettings["limit_date_new"]) > 0)
  ) {
    $dealer_input = $listingSettings["limit_date_new"];
  }

  return $dealer_input;
}

//get limit date used
function get_limit_date_used()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["limit_date_used"])
    && !empty($listingSettings["limit_date_used"]) && (strlen($listingSettings["limit_date_used"]) > 0)
  ) {
    $dealer_input = $listingSettings["limit_date_used"];
  }

  return $dealer_input;
}


//get activate limit date
function get_activate_limit_date()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["activate_limit_date"])
    && !empty($listingSettings["activate_limit_date"]) && (strlen($listingSettings["activate_limit_date"]) > 0)
  ) {
    $dealer_input = $listingSettings["activate_limit_date"];
  }

  return $dealer_input;
}

//get activate limit date used
function get_activate_limit_date_used()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["activate_limit_date_used"])
    && !empty($listingSettings["activate_limit_date_used"]) && (strlen($listingSettings["activate_limit_date_used"]) > 0)
  ) {
    $dealer_input = $listingSettings["activate_limit_date_used"];
  }

  return $dealer_input;
}

function has_passed_limit_date() {
  $limit_date = function_exists('get_limit_date_new') ? get_limit_date_new() : null;
  $current_date = date('Y-m-d');
  $activate_limit_date = function_exists('get_activate_limit_date') ? get_activate_limit_date() : 'Disabled';

  // Verificar si la fecha límite es válida
  if (!$limit_date) {
      return false;
  }

  // Convertir fechas a objetos DateTime
  $limit_date_obj = DateTime::createFromFormat('Y-m-d', $limit_date);
  $current_date_obj = DateTime::createFromFormat('Y-m-d', $current_date);

  if (!$limit_date_obj) {
      return false; // Si la fecha límite no se pudo convertir, retornamos false
  }

  return ($activate_limit_date === 'Enabled' && $limit_date_obj < $current_date_obj);
}

function has_passed_limit_date_used() {
  $limit_date = function_exists('get_limit_date_used') ? get_limit_date_used() : null;
  $current_date = date('Y-m-d');
  $activate_limit_date = function_exists('get_activate_limit_date_used') ? get_activate_limit_date_used() : 'Disabled';

  // Verificar si la fecha límite es válida
  if (!$limit_date) {
      return false;
  }

  // Convertir fechas a objetos DateTime
  $limit_date_obj = DateTime::createFromFormat('Y-m-d', $limit_date);
  $current_date_obj = DateTime::createFromFormat('Y-m-d', $current_date);

  if (!$limit_date_obj) {
      return false; // Si la fecha límite no es válida, retorna false
  }

  return ($activate_limit_date === 'Enabled' && $limit_date_obj < $current_date_obj);
}


//get listing image used
function get_listing_image_used()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["image_used"])
    && !empty($listingSettings["image_used"]) && (strlen($listingSettings["image_used"]) > 0)
  ) {
    $dealer_input = $listingSettings["image_used"];
  }

  return $dealer_input;
}

//get listing link used
function get_listing_link_used()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["link_used"])
    && !empty($listingSettings["link_used"]) && (strlen($listingSettings["link_used"]) > 0)
  ) {
    $dealer_input = $listingSettings["link_used"];
  }

  return $dealer_input;
}

//get listing image used fr
function get_listing_image_used_fr()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["image_used_fr"])
    && !empty($listingSettings["image_used_fr"]) && (strlen($listingSettings["image_used_fr"]) > 0)
  ) {
    $dealer_input = $listingSettings["image_used_fr"];
  }

  return $dealer_input;
}

//get listing link used fr
function get_listing_link_used_fr()
{
  $dealer_input = "";
  $listingSettings = get_dealer_listings();
  if (
    isset($listingSettings) && !empty($listingSettings) && isset($listingSettings["link_used_fr"])
    && !empty($listingSettings["link_used_fr"]) && (strlen($listingSettings["link_used_fr"]) > 0)
  ) {
    $dealer_input = $listingSettings["link_used_fr"];
  }

  return $dealer_input;
}


/* -------------------------------------------------------------------------
 * LBT-1462 — Multiple inventory-insert images (repeatable list)
 *
 * The legacy feature stored a single image per (new|used) x (en|fr) slot in
 * the flat option `dealer-settings-listing-options`. This adds a repeatable
 * list stored in `dealer-settings-listing-images-options` (an array of
 * entries). `get_listing_images()` is the single source of truth for the SRP
 * render: when the repeater is empty it transparently migrates the legacy
 * flat keys into equivalent entries, so existing single-image configs keep
 * working without a data write.
 * ---------------------------------------------------------------------- */

//raw repeater option (array of entries) or empty array
function get_dealer_listing_images()
{
  $entries = get_option('dealer-settings-listing-images-options');
  return is_array($entries) ? $entries : array();
}

/**
 * Global config for how the listing-insert images are placed:
 *   mode   'grouped' (default) | 'individual'
 *   offset cards between insertions (grouped mode)
 *   repeat number of full cycles (grouped mode); 0 = repeat until inventory ends
 *
 * Stored in the companion option `dealer-settings-listing-images-config`.
 * Defaults to grouped with the legacy interval as offset so existing
 * single-image configs keep inserting exactly as before.
 */
function get_listing_images_config()
{
  $cfg = get_option('dealer-settings-listing-images-config');
  $cfg = is_array($cfg) ? $cfg : array();

  $mode = isset($cfg['mode']) ? strtolower(trim($cfg['mode'])) : 'grouped';
  if (!in_array($mode, array('grouped', 'individual'), true)) {
    $mode = 'grouped';
  }

  $legacyInterval = function_exists('get_insert_after_new') ? (int) get_insert_after_new() : 0;
  $offset = isset($cfg['offset']) && $cfg['offset'] !== '' ? max(0, (int) $cfg['offset']) : $legacyInterval;
  $repeat = isset($cfg['repeat']) ? max(0, (int) $cfg['repeat']) : 0;

  return array(
    'mode'   => $mode,
    'offset' => $offset,
    'repeat' => $repeat,
  );
}

//fill defaults + cast a single entry to a stable shape
function normalize_listing_image_entry($entry)
{
  $entry = is_array($entry) ? $entry : array();

  $condition = isset($entry['condition']) ? strtolower(trim($entry['condition'])) : 'both';
  if (!in_array($condition, array('new', 'used', 'both'), true)) {
    $condition = 'both';
  }

  $language = isset($entry['language']) ? strtolower(trim($entry['language'])) : 'both';
  if (!in_array($language, array('en', 'fr', 'both'), true)) {
    $language = 'both';
  }

  $target = isset($entry['target']) ? trim($entry['target']) : '_self';
  if (!in_array($target, array('_self', '_blank'), true)) {
    $target = '_self';
  }

  $activate = isset($entry['activate_limit_date']) ? trim($entry['activate_limit_date']) : 'Disabled';
  $activate = ($activate === 'Enabled') ? 'Enabled' : 'Disabled';

  // How the image sits in its card: 'contain' letterboxes (no crop, default),
  // 'cover' fills and crops. Default 'contain' to never lose promo content.
  $fit = isset($entry['fit']) ? strtolower(trim($entry['fit'])) : 'contain';
  if (!in_array($fit, array('cover', 'contain'), true)) {
    $fit = 'contain';
  }

  return array(
    'image'               => isset($entry['image']) ? trim($entry['image']) : '',
    'link'                => isset($entry['link']) ? trim($entry['link']) : '',
    'target'              => $target,
    'insert_after'        => isset($entry['insert_after']) ? max(0, (int) $entry['insert_after']) : 0,
    'repeat_every'        => isset($entry['repeat_every']) ? max(0, (int) $entry['repeat_every']) : 0,
    'condition'           => $condition,
    'language'            => $language,
    'fit'                 => $fit,
    'limit_date'          => isset($entry['limit_date']) ? trim($entry['limit_date']) : '',
    'activate_limit_date' => $activate,
    'alt'                 => isset($entry['alt']) ? trim($entry['alt']) : '',
  );
}

//build entries from the legacy flat keys (backwards-compat migration on read)
function migrate_legacy_listing_images()
{
  // Legacy behaviour REPEATS each image every `insert_after_new` cards (a single
  // global interval drove both New and Used). Preserve that by migrating to a
  // repeating entry (repeat_every = interval), not a one-time insert.
  $interval = function_exists('get_insert_after_new') ? (int) get_insert_after_new() : 0;

  $legacy = array(
    // image getter, link getter, condition, language, limit_date getter, activate getter
    array('get_listing_image_new',     'get_listing_link_new',     'new',  'en', 'get_limit_date_new',  'get_activate_limit_date'),
    array('get_listing_image_new_fr',  'get_listing_link_new_fr',  'new',  'fr', 'get_limit_date_new',  'get_activate_limit_date'),
    array('get_listing_image_used',    'get_listing_link_used',    'used', 'en', 'get_limit_date_used', 'get_activate_limit_date_used'),
    array('get_listing_image_used_fr', 'get_listing_link_used_fr', 'used', 'fr', 'get_limit_date_used', 'get_activate_limit_date_used'),
  );

  $entries = array();
  foreach ($legacy as $row) {
    list($imageFn, $linkFn, $condition, $language, $limitFn, $activateFn) = $row;
    $image = function_exists($imageFn) ? $imageFn() : '';
    if (empty($image)) {
      continue; // only migrate configured slots
    }
    $entries[] = normalize_listing_image_entry(array(
      'image'               => $image,
      'link'                => function_exists($linkFn) ? $linkFn() : '',
      'target'              => '_self',
      'insert_after'        => 0,
      'repeat_every'        => $interval, // reproduce the legacy "repeat every N" behaviour
      'condition'           => $condition,
      'language'            => $language,
      'fit'                 => 'contain', // preserve the legacy natural (no-crop) look
      'limit_date'          => function_exists($limitFn) ? $limitFn() : '',
      'activate_limit_date' => function_exists($activateFn) ? $activateFn() : 'Disabled',
      'alt'                 => '',
    ));
  }

  return $entries;
}

//single source of truth for the SRP render: normalized list, migrated when empty
function get_listing_images()
{
  $entries = get_dealer_listing_images();

  if (!empty($entries)) {
    return array_values(array_filter(array_map('normalize_listing_image_entry', $entries), function ($e) {
      return !empty($e['image']);
    }));
  }

  return migrate_legacy_listing_images();
}

//whether any listing-insert image is configured (new + legacy)
function has_dealer_listing_images()
{
  $images = get_listing_images();
  return !empty($images);
}

//per-entry expiration (mirrors has_passed_limit_date but scoped to one entry)
function listing_image_entry_expired($entry)
{
  $entry = normalize_listing_image_entry($entry);

  if ($entry['activate_limit_date'] !== 'Enabled') {
    return false;
  }
  if (empty($entry['limit_date'])) {
    return false;
  }

  $limit_date_obj = DateTime::createFromFormat('Y-m-d', $entry['limit_date']);
  if (!$limit_date_obj) {
    return false;
  }
  $current_date_obj = DateTime::createFromFormat('Y-m-d', date('Y-m-d'));

  return ($limit_date_obj < $current_date_obj);
}

/**
 * LBT-1462 Round 3: resolve a reusable listing-image group (created in the plugin,
 * option `lbx_listing_image_groups`) into the same shape the SRP render pipeline
 * already consumes — entries[] (normalized) + config{ mode, start, offset, repeat }.
 *
 * Returns null when the group is missing, disabled, or its group-level expiration
 * date has passed (which hides the whole group). Per-image language + expiration are
 * NOT applied here — the blade's existing entry filter handles those uniformly for
 * both the group and the legacy/global source.
 *
 * @param string $group_id  Group id chosen in the Inventory block ('' = none).
 * @return array|null ['config' => [...], 'entries' => [...]] or null.
 */
function get_listing_image_group($group_id)
{
  if (empty($group_id)) {
    return null;
  }

  $groups = get_option('lbx_listing_image_groups', array());
  if (!is_array($groups) || !isset($groups[$group_id]) || !is_array($groups[$group_id])) {
    return null;
  }
  $group = $groups[$group_id];

  // Inactive groups render nothing.
  if (empty($group['active'])) {
    return null;
  }

  // Group-level expiration hides the entire group once the date has passed.
  if (!empty($group['date_enabled']) && !empty($group['limit_date'])) {
    $limit = DateTime::createFromFormat('Y-m-d', $group['limit_date']);
    $today = DateTime::createFromFormat('Y-m-d', date('Y-m-d'));
    if ($limit && $today && $limit < $today) {
      return null;
    }
  }

  $offset = isset($group['offset']) ? max(1, (int) $group['offset']) : 1;

  $images  = (isset($group['images']) && is_array($group['images'])) ? $group['images'] : array();
  $entries = array();
  foreach ($images as $img) {
    if (!is_array($img)) {
      continue;
    }
    // Only active images render (manual on/off). Missing key = active (defensive).
    if (array_key_exists('active', $img) && empty($img['active'])) {
      continue;
    }
    // Map the group image shape to the render entry shape. Position lives on the
    // group (offset), so per-entry insert_after/repeat_every are 0. Condition and
    // language are forced to 'both': a group image shows regardless of the vehicle's
    // new/used status or the page language. The per-image date toggle maps to
    // activate_limit_date so the shared listing_image_entry_expired() filter in the
    // blade drops expired images.
    $entries[] = normalize_listing_image_entry(array(
      'image'               => isset($img['image']) ? $img['image'] : '',
      'link'                => isset($img['link']) ? $img['link'] : '',
      'target'              => isset($img['target']) ? $img['target'] : '_self',
      'insert_after'        => 0,
      'repeat_every'        => 0,
      'condition'           => 'both',
      'language'            => 'both',
      'fit'                 => isset($img['fit']) ? $img['fit'] : 'contain',
      'limit_date'          => isset($img['limit_date']) ? $img['limit_date'] : '',
      'activate_limit_date' => !empty($img['date_enabled']) ? 'Enabled' : 'Disabled',
      'alt'                 => isset($img['alt']) ? $img['alt'] : '',
    ));
  }

  return array(
    // Groups always cycle (grouped mode). No `start` — the first image lands on card
    // `offset` (spa-inventory falls back to start=offset when start is absent).
    // `repeat` = 0 means "until the end of the SRP" (images repeat indefinitely).
    'config'  => array('mode' => 'grouped', 'offset' => $offset, 'repeat' => 0),
    'entries' => $entries,
  );
}


function get_calculated_msrp_label()
{
  if (get_locale() == 'fr_CA') {
    return get_calculated_msrp_fr_label();
  } else {
    return get_calculated_msrp_en_label();
  }
}

function get_calculated_msrp_en_label()
{
  $dealer_input = "Basic MSRP";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["calculated_msrp"])
    && !empty($labelSettings["calculated_msrp"]) && (strlen($labelSettings["calculated_msrp"]) > 0)
  ) {
    $dealer_input = $labelSettings["calculated_msrp"];
  }

  return $dealer_input;

}

function get_calculated_msrp_fr_label()
{
  $dealer_input = "PDSF de base";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["calculated_msrp_fr"])
    && !empty($labelSettings["calculated_msrp_fr"]) && (strlen($labelSettings["calculated_msrp_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["calculated_msrp_fr"];
  }

  return $dealer_input;

}

function get_vehicle_price_label($condition = null)
{
  if(!$condition)
    $condition = "new";

  if($condition == "new"){
    return get_new_vehicle_price_label();
  }
  else {
    return get_used_vehicle_price_label();
  }
}

function get_new_vehicle_price_label()
{
  if (get_locale() == 'fr_CA') {
    return get_new_vehicle_price_fr_label();
  } else {
    return get_new_vehicle_price_en_label();
  }
}

function get_new_vehicle_price_en_label()
{
  $dealer_input = "MSRP";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["new_vehicle_price"])
    && !empty($labelSettings["new_vehicle_price"]) && (strlen($labelSettings["new_vehicle_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["new_vehicle_price"];
  }

  return $dealer_input;

}

function get_new_vehicle_price_fr_label()
{
  $dealer_input = "PDSF";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["new_vehicle_price_fr"])
    && !empty($labelSettings["new_vehicle_price_fr"]) && (strlen($labelSettings["new_vehicle_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["new_vehicle_price_fr"];
  }

  return $dealer_input;

}

function get_after_discount_price_label($condition = null)
{
  if(!$condition)
    $condition = "new";

  if($condition == "new"){
    if (get_locale() == 'fr_CA') {
      return get_after_discount_price_fr_label();
    } else {
      return get_after_discount_price_en_label();
    }
  }
  else {
     if (get_locale() == 'fr_CA') {
      return get_used_after_discount_price_fr_label();
    } else {
      return get_used_after_discount_price_en_label();
    }
  }

}

function get_after_discount_price_en_label()
{
  $dealer_input = "";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["after_discount_price"])
    && !empty($labelSettings["after_discount_price"]) && (strlen($labelSettings["after_discount_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["after_discount_price"];
  }

  return $dealer_input;

}

function get_after_discount_price_fr_label()
{
  $dealer_input = "";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["after_discount_price_fr"])
    && !empty($labelSettings["after_discount_price_fr"]) && (strlen($labelSettings["after_discount_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["after_discount_price_fr"];
  }

  return $dealer_input;

}

function get_used_after_discount_price_en_label()
{
  $dealer_input = "";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["used_after_discount_price"])
    && !empty($labelSettings["used_after_discount_price"]) && (strlen($labelSettings["used_after_discount_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["used_after_discount_price"];
  }
  else if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["after_discount_price"])
    && !empty($labelSettings["after_discount_price"]) && (strlen($labelSettings["after_discount_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["after_discount_price"];
  }

  return $dealer_input;

}

function get_used_after_discount_price_fr_label()
{
  $dealer_input = "";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["used_after_discount_price_fr"])
    && !empty($labelSettings["used_after_discount_price_fr"]) && (strlen($labelSettings["used_after_discount_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["used_after_discount_price_fr"];
  }
  else if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["after_discount_price_fr"])
    && !empty($labelSettings["after_discount_price_fr"]) && (strlen($labelSettings["after_discount_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["after_discount_price_fr"];
  }

  return $dealer_input;

}

function get_special_price_label()
{
  if (get_locale() == 'fr_CA') {
    return get_special_price_fr_label();
  } else {
    return get_special_price_en_label();
  }
}


function get_special_price_en_label()
{
  $dealer_input = "Special Price";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_price"])
    && !empty($labelSettings["special_price"]) && (strlen($labelSettings["special_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["special_price"];
  }

  return $dealer_input;

}

function get_special_price_fr_label()
{
  $dealer_input = "Prix spéciale";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_price_fr"])
    && !empty($labelSettings["special_price_fr"]) && (strlen($labelSettings["special_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["special_price_fr"];
  }

  return $dealer_input;

}

function get_special_discount_label()
{
  if (get_locale() == 'fr_CA') {
    return get_special_discount_fr_label();
  } else {
    return get_special_discount_en_label();
  }
}

function get_special_discount_en_label()
{
  $dealer_input = "Special Discount";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_discount_price"])
    && !empty($labelSettings["special_discount_price"]) && (strlen($labelSettings["special_discount_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["special_discount_price"];
  }

  return $dealer_input;

}

function get_special_discount_fr_label()
{
  $dealer_input = "Remise spéciale";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_discount_price_fr"])
    && !empty($labelSettings["special_discount_price_fr"]) && (strlen($labelSettings["special_discount_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["special_discount_price_fr"];
  }

  return $dealer_input;

}

//! Helper tag custom funcion

function getTagStyles($colorLabel, $limitLabel, $version) {
  $backgroundColor = $colorLabel != '#000000' ? "background-color: $colorLabel !important;" : '';
  $adjustedLimitLabel = $version === 1 ? $limitLabel + 1 : $limitLabel; // Sumar 2 al valor original
  $characterTrunk = $limitLabel > 0 ? "width: {$adjustedLimitLabel}ch; display:inline-block;" : 'display: inline-block; white-space: nowrap;';
  return [
      'backgroundColor' => $backgroundColor,
      'characterTrunk' => $characterTrunk
  ];
}

//! Sale pending tags

function get_salepending_tag_label()
{
  if (get_locale() == 'fr_CA') {
    return get_salepending_tag_fr_label();
  } else {
    return get_salepending_tag_en_label();
  }
}

function get_salepending_tag_en_label()
{
  $dealer_input = "Sale Pending";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["salepending_tag_label"])
    && !empty($labelSettings["salepending_tag_label"]) && (strlen($labelSettings["salepending_tag_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["salepending_tag_label"];
  }

  return $dealer_input;
}

function get_salepending_tag_fr_label()
{
  $dealer_input = "Vente en cours";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["salepending_tag_label_fr"])
    && !empty($labelSettings["salepending_tag_label_fr"]) && (strlen($labelSettings["salepending_tag_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["salepending_tag_label_fr"];
  }

  return $dealer_input;
}

// color tag salepending
function get_salepending_tag_color_label()
{
  $dealer_input = "bg-primary";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["salepending_tag_label_color"])
    && !empty($labelSettings["salepending_tag_label_color"]) && (strlen($labelSettings["salepending_tag_label_color"]) != "#000000")
  ) {
    $dealer_input = $labelSettings["salepending_tag_label_color"];
  }

  return $dealer_input;
}
// limit tag salepending
function get_salepending_tag_limit_label()
{
  $dealer_input = 0;
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["salepending_tag_label_limit"])
    && !empty($labelSettings["salepending_tag_label_limit"]) && ($labelSettings["salepending_tag_label_limit"] > 0)
  ) {
    $dealer_input = $labelSettings["salepending_tag_label_limit"];
  }

  return $dealer_input;
}

//! special tag

function get_special_tag_label()
{
  if (get_locale() == 'fr_CA') {
    return get_special_tag_fr_label();
  } else {
    return get_special_tag_en_label();
  }
}

function get_special_tag_en_label()
{
  $dealer_input = "Special";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_tag_label"])
    && !empty($labelSettings["special_tag_label"]) && (strlen($labelSettings["special_tag_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["special_tag_label"];
  }

  return $dealer_input;
}

function get_special_tag_fr_label()
{
  $dealer_input = "Spéciaux";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_tag_label_fr"])
    && !empty($labelSettings["special_tag_label_fr"]) && (strlen($labelSettings["special_tag_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["special_tag_label_fr"];
  }

  return $dealer_input;
}

// color tag special
function get_special_tag_color_label()
{
  $dealer_input = "bg-primary";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_tag_label_color"])
    && !empty($labelSettings["special_tag_label_color"]) && (strlen($labelSettings["special_tag_label_color"]) != "#000000")
  ) {
    $dealer_input = $labelSettings["special_tag_label_color"];
  }

  return $dealer_input;
}
// limit tag special
function get_special_tag_limit_label()
{
  $dealer_input = 0;
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["special_tag_label_limit"])
    && !empty($labelSettings["special_tag_label_limit"]) && ($labelSettings["special_tag_label_limit"] > 0)
  ) {
    $dealer_input = $labelSettings["special_tag_label_limit"];
  }

  return $dealer_input;
}

//! certified tag

function get_certified_tag_label()
{
  if (get_locale() == 'fr_CA') {
    return get_certified_tag_fr_label();
  } else {
    return get_certified_tag_en_label();
  }
}

function get_certified_tag_en_label()
{
  $dealer_input = "Certified";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["certified_tag_label"])
    && !empty($labelSettings["certified_tag_label"]) && (strlen($labelSettings["certified_tag_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["certified_tag_label"];
  }

  return $dealer_input;
}

function get_certified_tag_fr_label()
{
  $dealer_input = "Certifié";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["certified_tag_label_fr"])
    && !empty($labelSettings["certified_tag_label_fr"]) && (strlen($labelSettings["certified_tag_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["certified_tag_label_fr"];
  }

  return $dealer_input;
}

// color tag certified
function get_certified_tag_color_label()
{
  $dealer_input = "bg-primary";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["certified_tag_label_color"])
    && !empty($labelSettings["certified_tag_label_color"]) && (strlen($labelSettings["certified_tag_label_color"]) != "#000000")
  ) {
    $dealer_input = $labelSettings["certified_tag_label_color"];
  }

  return $dealer_input;
}
// limit tag certified
function get_certified_tag_limit_label()
{
  $dealer_input = 0;
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["certified_tag_label_limit"])
    && !empty($labelSettings["certified_tag_label_limit"]) && ($labelSettings["certified_tag_label_limit"] > 0)
  ) {
    $dealer_input = $labelSettings["certified_tag_label_limit"];
  }

  return $dealer_input;
}

//! asis tag

function get_asis_tag_label()
{
  if (get_locale() == 'fr_CA') {
    return get_asis_tag_fr_label();
  } else {
    return get_asis_tag_en_label();
  }
}

function get_asis_tag_en_label()
{
  $dealer_input = "As Is";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["asis_tag_label"])
    && !empty($labelSettings["asis_tag_label"]) && (strlen($labelSettings["asis_tag_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["asis_tag_label"];
  }

  return $dealer_input;
}

function get_asis_tag_fr_label()
{
  $dealer_input = "Comme si";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["asis_tag_label_fr"])
    && !empty($labelSettings["asis_tag_label_fr"]) && (strlen($labelSettings["asis_tag_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["asis_tag_label_fr"];
  }

  return $dealer_input;
}

// color tag asis
function get_asis_tag_color_label()
{
  $dealer_input = "bg-primary";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["asis_tag_label_color"])
    && !empty($labelSettings["asis_tag_label_color"]) && (strlen($labelSettings["asis_tag_label_color"]) != "#000000")
  ) {
    $dealer_input = $labelSettings["asis_tag_label_color"];
  }

  return $dealer_input;
}
// limit tag asis
function get_asis_tag_limit_label()
{
  $dealer_input = 0;
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["asis_tag_label_limit"])
    && !empty($labelSettings["asis_tag_label_limit"]) && ($labelSettings["asis_tag_label_limit"] > 0)
  ) {
    $dealer_input = $labelSettings["asis_tag_label_limit"];
  }

  return $dealer_input;
}

//! incoming tag

function get_incoming_tag_label()
{
  if (get_locale() == 'fr_CA') {
    return get_incoming_tag_fr_label();
  } else {
    return get_incoming_tag_en_label();
  }
}


function get_incoming_tag_en_label()
{
  $dealer_input = "Incoming";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["incoming_tag_label"])
    && !empty($labelSettings["incoming_tag_label"]) && (strlen($labelSettings["incoming_tag_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["incoming_tag_label"];
  }

  return $dealer_input;
}

function get_incoming_tag_fr_label()
{
  $dealer_input = "En transit";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["incoming_tag_label_fr"])
    && !empty($labelSettings["incoming_tag_label_fr"]) && (strlen($labelSettings["incoming_tag_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["incoming_tag_label_fr"];
  }

  return $dealer_input;
}
// color tag incoming
function get_incoming_tag_color_label()
{
  $dealer_input = "bg-primary";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["incoming_tag_label_color"])
    && !empty($labelSettings["incoming_tag_label_color"]) && (strlen($labelSettings["incoming_tag_label_color"]) != "#000000")
  ) {
    $dealer_input = $labelSettings["incoming_tag_label_color"];
  }

  return $dealer_input;
}
// limit tag incoming
function get_incoming_tag_limit_label()
{
  $dealer_input = 0;
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["incoming_tag_label_limit"])
    && !empty($labelSettings["incoming_tag_label_limit"]) && ($labelSettings["incoming_tag_label_limit"] > 0)
  ) {
    $dealer_input = $labelSettings["incoming_tag_label_limit"];
  }

  return $dealer_input;
}

//! Demo Tags

function get_demo_tag_label()
{
  if (get_locale() == 'fr_CA') {
    return get_demo_tag_fr_label();
  } else {
    return get_demo_tag_en_label();
  }
}
function get_demo_tag_en_label()
{
  $dealer_input = "Demo";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["demo_tag_label"])
    && !empty($labelSettings["demo_tag_label"]) && (strlen(trim($labelSettings["demo_tag_label"])) > 0)
  ) {
    $dealer_input = $labelSettings["demo_tag_label"];
  }

  return $dealer_input;
}

function get_demo_tag_fr_label()
{
  $dealer_input = "Démo";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["demo_tag_label_fr"])
    && !empty($labelSettings["demo_tag_label_fr"]) && (strlen(trim($labelSettings["demo_tag_label_fr"])) > 0)
  ) {
    $dealer_input = $labelSettings["demo_tag_label_fr"];
  }

  return $dealer_input;
}
// color tag demo
function get_demo_tag_color_label()
{
  $dealer_input = "bg-primary";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["demo_tag_label_color"])
    && !empty($labelSettings["demo_tag_label_color"]) && (strlen($labelSettings["demo_tag_label_color"]) != "#000000")
  ) {
    $dealer_input = $labelSettings["demo_tag_label_color"];
  }

  return $dealer_input;
}
// limit tag demo
function get_demo_tag_limit_label()
{
  $dealer_input = 0;
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["demo_tag_label_limit"])
    && !empty($labelSettings["demo_tag_label_limit"]) && ($labelSettings["demo_tag_label_limit"] > 0)
  ) {
    $dealer_input = $labelSettings["demo_tag_label_limit"];
  }

  return $dealer_input;
}

function get_tax_and_lic_label($condition = "NEW", $include_tax = false)
{
  if (get_locale() == 'fr_CA') {
    return get_tax_and_lic_fr_label($condition, $include_tax);
  } else {
    return get_tax_and_lic_en_label($condition, $include_tax);
  }
}
function get_tax_and_lic_label_asterix($condition = "NEW", $include_tax = false)
{
  if (get_locale() == 'fr_CA') {
    return get_tax_and_lic_fr_label($condition, $include_tax) . " *";
  } else {
    return get_tax_and_lic_en_label($condition, $include_tax) . " *";
  }
}

function get_tax_and_lic_en_label($condition = "NEW", $include_tax = false)
{
  $dealer_input = $include_tax ? "+ Lic" : "+ Tax & Lic";
  $labelSettings = get_dealer_labels();

  if (strtoupper($condition) === "USED") {
    if (
      isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["used_tax_and_lic_label"])
      && !empty($labelSettings["used_tax_and_lic_label"]) && (strlen($labelSettings["used_tax_and_lic_label"]) > 0)
    ) {
      $dealer_input = $include_tax ? "" : $labelSettings["used_tax_and_lic_label"];
    } elseif (
              isset($labelSettings) && !empty($labelSettings)
              && isset($labelSettings["used_tax_label"]) && !empty($labelSettings["used_tax_label"]) && (strlen($labelSettings["used_tax_label"]) > 0)
              && isset($labelSettings["used_lic_label"]) && !empty($labelSettings["used_lic_label"]) && (strlen($labelSettings["used_lic_label"]) > 0)
              ) {
              $dealer_input = $include_tax ? "+ " . $labelSettings["used_lic_label"] : "+ " . $labelSettings["used_tax_label"] . " & " .  $labelSettings["used_lic_label"];
    }
  } else {
    if (
      isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["tax_and_lic_label"])
      && !empty($labelSettings["tax_and_lic_label"]) && (strlen($labelSettings["tax_and_lic_label"]) > 0)
    ) {
      $dealer_input = $include_tax ? "" : $labelSettings["tax_and_lic_label"];
    } elseif (
              isset($labelSettings) && !empty($labelSettings)
              && isset($labelSettings["new_tax_label"]) && !empty($labelSettings["new_tax_label"]) && (strlen($labelSettings["new_tax_label"]) > 0)
              && isset($labelSettings["new_lic_label"]) && !empty($labelSettings["new_lic_label"]) && (strlen($labelSettings["new_lic_label"]) > 0)
              ) {
              $dealer_input = $include_tax ? "+ " . $labelSettings["new_lic_label"] : "+ " . $labelSettings["new_tax_label"] . " & " .  $labelSettings["new_lic_label"];
    }
  }

  return $dealer_input;

}

function get_tax_and_lic_fr_label($condition = "NEW", $include_tax = false)
{
  $dealer_input = $include_tax ? "+ Imm." : "+ Taxes et Imm";
  $labelSettings = get_dealer_labels();

  if (strtoupper($condition) === "USED") {
    if (
      isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["used_tax_and_lic_label_fr"])
      && !empty($labelSettings["used_tax_and_lic_label_fr"]) && (strlen($labelSettings["used_tax_and_lic_label_fr"]) > 0)
    ) {
      $dealer_input = $include_tax ? "" : $labelSettings["used_tax_and_lic_label_fr"];
    } elseif (
              isset($labelSettings) && !empty($labelSettings)
              && isset($labelSettings["used_tax_label_fr"]) && !empty($labelSettings["used_tax_label_fr"]) && (strlen($labelSettings["used_tax_label_fr"]) > 0)
              && isset($labelSettings["used_lic_label_fr"]) && !empty($labelSettings["used_lic_label_fr"]) && (strlen($labelSettings["used_lic_label_fr"]) > 0)
              ) {
              $dealer_input = $include_tax ? "+ " . $labelSettings["used_lic_label_fr"] : "+ " . $labelSettings["used_tax_label_fr"] . " et " .  $labelSettings["used_lic_label_fr"];
    }
  } else {
    if (
      isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["tax_and_lic_label_fr"])
      && !empty($labelSettings["tax_and_lic_label_fr"]) && (strlen($labelSettings["tax_and_lic_label_fr"]) > 0)
    ) {
      $dealer_input = $include_tax ? "" : $labelSettings["tax_and_lic_label_fr"];
    } elseif (
              isset($labelSettings) && !empty($labelSettings)
              && isset($labelSettings["new_tax_label_fr"]) && !empty($labelSettings["new_tax_label_fr"]) && (strlen($labelSettings["new_tax_label_fr"]) > 0)
              && isset($labelSettings["new_lic_label_fr"]) && !empty($labelSettings["new_lic_label_fr"]) && (strlen($labelSettings["new_lic_label_fr"]) > 0)
              ) {
              $dealer_input = $include_tax ? "+ " . $labelSettings["new_lic_label_fr"] : "+ " . $labelSettings["new_tax_label_fr"] . " et " .  $labelSettings["new_lic_label_fr"];
    }
  }

  return $dealer_input;

}

function get_tax_and_lic_en_label_asterix()
{
  $dealer_input = "+ Tax & Lic *";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["tax_and_lic_label"])
    && !empty($labelSettings["tax_and_lic_label"]) && (strlen($labelSettings["tax_and_lic_label"]) > 0)
  ) {
    $dealer_input = "+ Tax & Lic *";
  }

  return $dealer_input;

}

function get_tax_and_lic_fr_label_asterix()
{
  $dealer_input = "+ taxes et imm.";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["tax_and_lic_label_fr"])
    && !empty($labelSettings["tax_and_lic_label_fr"]) && (strlen($labelSettings["tax_and_lic_label_fr"]) > 0)
  ) {
    $dealer_input = "+ taxes et imm. *";
  }

  return $dealer_input;

}

function get_rebates_label()
{
  if (get_locale() == 'fr_CA') {
    return get_rebates_fr_label();
  } else {
    return get_rebates_en_label();
  }
}

function get_rebates_en_label()
{
  $dealer_input = "Discounts and Rebates";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["rebates_label"])
    && !empty($labelSettings["rebates_label"]) && (strlen($labelSettings["rebates_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["rebates_label"];
  }

  return $dealer_input;

}

function get_rebates_fr_label()
{
  $dealer_input = "Réductions et rabais";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["rebates_label_fr"])
    && !empty($labelSettings["rebates_label_fr"]) && (strlen($labelSettings["rebates_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["rebates_label_fr"];
  }

  return $dealer_input;

}

function get_additional_rebates_label()
{
  if (get_locale() == 'fr_CA') {
    return get_additional_rebates_fr_label();
  } else {
    return get_additional_rebates_en_label();
  }
}

function get_additional_rebates_en_label()
{
  $dealer_input = "Additional Rebate";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["additional_rebates_label"])
    && !empty($labelSettings["additional_rebates_label"]) && (strlen($labelSettings["additional_rebates_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["additional_rebates_label"];
  }

  return $dealer_input;

}

function get_additional_rebates_fr_label()
{
  $dealer_input = "Rabais supplémentaires";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["additional_rebates_label_fr"])
    && !empty($labelSettings["additional_rebates_label_fr"]) && (strlen($labelSettings["additional_rebates_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["additional_rebates_label_fr"];
  }

  return $dealer_input;

}

function get_used_vehicle_price_label()
{
  if (get_locale() == 'fr_CA') {
    return get_used_vehicle_price_fr_label();
  } else {
    return get_used_vehicle_price_en_label();
  }
}

function get_used_vehicle_price_en_label()
{
  $dealer_input = "Vehicle Price";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["used_vehicle_price"])
    && !empty($labelSettings["used_vehicle_price"]) && (strlen($labelSettings["used_vehicle_price"]) > 0)
  ) {
    $dealer_input = $labelSettings["used_vehicle_price"];
  }

  return $dealer_input;
}

function get_used_vehicle_price_fr_label()
{
  $dealer_input = "Prix ​​du véhicule";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["used_vehicle_price_fr"])
    && !empty($labelSettings["used_vehicle_price_fr"]) && (strlen($labelSettings["used_vehicle_price_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["used_vehicle_price_fr"];
  }

  return $dealer_input;

}

function get_phone_sales_label()
{
  if (get_locale() == 'fr_CA') {
    return get_phone_sales_fr_label();
  } else {
    return get_phone_sales_en_label();
  }
}

function get_phone_sales_en_label()
{
  $dealer_input = "Sales";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_sales_label"])
    && !empty($labelSettings["phone_sales_label"]) && (strlen($labelSettings["phone_sales_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_sales_label"];
  }

  return $dealer_input;

}

function get_phone_sales_fr_label()
{
  $dealer_input = "Ventes";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_sales_label_fr"])
    && !empty($labelSettings["phone_sales_label_fr"]) && (strlen($labelSettings["phone_sales_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_sales_label_fr"];
  }

  return $dealer_input;

}

function get_phone_parts_label()
{
  if (get_locale() == 'fr_CA') {
    return get_phone_parts_fr_label();
  } else {
    return get_phone_parts_en_label();
  }
}

function get_phone_parts_en_label()
{
  $dealer_input = "Parts";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_parts_label"])
    && !empty($labelSettings["phone_parts_label"]) && (strlen($labelSettings["phone_parts_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_parts_label"];
  }

  return $dealer_input;

}

function get_phone_parts_fr_label()
{
  $dealer_input = "Pièces";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_parts_label_fr"])
    && !empty($labelSettings["phone_parts_label_fr"]) && (strlen($labelSettings["phone_parts_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_parts_label_fr"];
  }

  return $dealer_input;

}

function get_phone_service_label()
{
  if (get_locale() == 'fr_CA') {
    return get_phone_service_fr_label();
  } else {
    return get_phone_service_en_label();
  }
}

function get_phone_service_en_label()
{
  $dealer_input = "Service";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_service_label"])
    && !empty($labelSettings["phone_service_label"]) && (strlen($labelSettings["phone_service_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_service_label"];
  }

  return $dealer_input;

}

function get_phone_service_fr_label()
{
  $dealer_input = "Service";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_service_label_fr"])
    && !empty($labelSettings["phone_service_label_fr"]) && (strlen($labelSettings["phone_service_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_service_label_fr"];
  }

  return $dealer_input;

}

function get_phone_fax_label()
{
  return isFrench()
    ? get_phone_fax_fr_label()
    : get_phone_fax_en_label();
}

function get_phone_fax_en_label()
{
  $dealer_input = "Fax";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_fax_label"])
    && !empty($labelSettings["phone_fax_label"]) && (strlen($labelSettings["phone_fax_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_fax_label"];
  }

  return $dealer_input;

}

function get_phone_fax_fr_label()
{
  $dealer_input = "Fax";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_fax_label_fr"])
    && !empty($labelSettings["phone_fax_label_fr"]) && (strlen($labelSettings["phone_fax_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_fax_label_fr"];
  }

  return $dealer_input;

}

function get_phone_body_shop_label()
{
  return isFrench()
    ? get_phone_body_shop_fr_label()
    : get_phone_body_shop_en_label();
}

function get_phone_body_shop_en_label()
{
  $dealer_input = "Body Shop";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_body_shop_label"])
    && !empty($labelSettings["phone_body_shop_label"]) && (strlen($labelSettings["phone_body_shop_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_body_shop_label"];
  }

  return $dealer_input;

}

function get_phone_body_shop_fr_label()
{
  $dealer_input = "Atelier de carrosserie";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_body_shop_label_fr"])
    && !empty($labelSettings["phone_body_shop_label_fr"]) && (strlen($labelSettings["phone_body_shop_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_body_shop_label_fr"];
  }

  return $dealer_input;

}

function get_phone_sms_label()
{
  return isFrench()
    ? get_phone_sms_fr_label()
    : get_phone_sms_en_label();
}

function get_phone_sms_en_label()
{
  $dealer_input = "SMS";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_sms_label"])
    && !empty($labelSettings["phone_sms_label"]) && (strlen($labelSettings["phone_sms_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_sms_label"];
  }

  return $dealer_input;

}

function get_phone_sms_fr_label()
{
  $dealer_input = "SMS";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_sms_label_fr"])
    && !empty($labelSettings["phone_sms_label_fr"]) && (strlen($labelSettings["phone_sms_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_sms_label_fr"];
  }

  return $dealer_input;

}

function get_phone_collision_label()
{
  return isFrench()
    ? get_phone_collision_fr_label()
    : get_phone_collision_en_label();
}

function get_phone_collision_en_label()
{
  $dealer_input = "Collision";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_collision_label"])
    && !empty($labelSettings["phone_collision_label"]) && (strlen($labelSettings["phone_collision_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_collision_label"];
  }

  return $dealer_input;

}

function get_phone_collision_fr_label()
{
  $dealer_input = "Collision";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_collision_label_fr"])
    && !empty($labelSettings["phone_collision_label_fr"]) && (strlen($labelSettings["phone_collision_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_collision_label_fr"];
  }

  return $dealer_input;

}

function get_phone_accessories_label()
{
  return isFrench()
    ? get_phone_accessories_fr_label()
    : get_phone_accessories_en_label();
}

function get_phone_accessories_en_label()
{
  $dealer_input = "Accessories";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_accessories_label"])
    && !empty($labelSettings["phone_accessories_label"]) && (strlen($labelSettings["phone_accessories_label"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_accessories_label"];
  }

  return $dealer_input;

}

function get_phone_accessories_fr_label()
{
  $dealer_input = "Accessoires";
  $labelSettings = get_dealer_labels();
  if (
    isset($labelSettings) && !empty($labelSettings) && isset($labelSettings["phone_accessories_label_fr"])
    && !empty($labelSettings["phone_accessories_label_fr"]) && (strlen($labelSettings["phone_accessories_label_fr"]) > 0)
  ) {
    $dealer_input = $labelSettings["phone_accessories_label_fr"];
  }

  return $dealer_input;

}


/* Hooks tester */
function test_hook()
{
  echo ('This hook works!');
}

function get_lbx_image_path($route)
{
  $fr_path = isFrench() ? 'fr/' : '';

  $childRoute = get_stylesheet_directory() . '/assets/images/' . $fr_path;
  $childRouteUri = get_stylesheet_directory_uri() . '/assets/images/' . $fr_path;

  $parentRouteUri = get_template_directory_uri() . '/resources/images/' . $fr_path;

  return file_exists($childRoute . $route)
    ? $childRouteUri . $route
    : $parentRouteUri . $route;
}

function url_exists($file)
{
  // $file_headers = @get_headers($file);
  // foreach($file_headers as $key => $value){
  //     if ($value == 'HTTP/1.1 404 Not Found'){
  //         return false;
  //     }
  // }
  return true;
}

//Exclude pages from WordPress Search
function french_time_format($str_time)
{
  $exploded_str_time = explode(':', $str_time);
  $hours = (strpos($str_time, 'pm') && $exploded_str_time[0] != 12) ?
    $exploded_str_time[0] + 12 :
    $exploded_str_time[0];

  $minutes = preg_replace(['/am/', '/pm/'], ['', ''], $exploded_str_time[1]);

  return $hours . 'h' . $minutes;
}

function get_dealer_french_hours($hours)
{
  foreach ($hours["sale"] as $key => $value)
    if ($value != 'Closed') {
      $exploded_time = explode('-', str_replace(' ', '', $value));
      $since_time = french_time_format($exploded_time[0]);
      $to_time = french_time_format($exploded_time[1]);
      $hours["sale"] = $since_time . " - " . $to_time;
    }
  foreach ($hours["service"] as $key => $value)
    if ($value != 'Closed') {
      $exploded_time = explode('-', str_replace(' ', '', $value));
      $since_time = french_time_format($exploded_time[0]);
      $to_time = french_time_format($exploded_time[1]);
      $hours["service"] = $since_time . " - " . $to_time;
    }
  foreach ($hours["parts"] as $key => $value)
    if ($value != 'Closed') {
      $exploded_time = explode('-', str_replace(' ', '', $value));
      $since_time = french_time_format($exploded_time[0]);
      $to_time = french_time_format($exploded_time[1]);
      $hours["parts"] = $since_time . " - " . $to_time;
    }

  return $hours;
}

function get_min_open_today($day)
{
  $hours = get_dealer_hours();
  $hours_additional_settings = get_dealer_hours_additional();
  $sale_hours = $hours["sale"];
  $service_hours = $hours["service"];
  $parts_hours = $hours["parts"];
  $exploded_time = explode('-', str_replace(' ', '', $sale_hours[ucfirst($day)]));
  $exploded_time_service = explode('-', str_replace(' ', '', $service_hours[ucfirst($day)]));
  $exploded_time_parts = explode('-', str_replace(' ', '', $parts_hours[ucfirst($day)]));
  $hours_array = [];

  if ($exploded_time[0] != 'Closed') {
    array_push($hours_array, date("H:i", strtotime($exploded_time[0])));
  }
  if ($exploded_time_service[0] != 'Closed' && $hours_additional_settings['servicehourstatus'] == 'Enabled') {
    array_push($hours_array, date("H:i", strtotime($exploded_time_service[0])));
  }
  if ($exploded_time_parts[0] != 'Closed' && $hours_additional_settings['parthourstatus'] == 'Enabled') {
    array_push($hours_array, date("H:i", strtotime($exploded_time_parts[0])));
  }

  if (count($hours_array) == 0)
    return 'Closed';

  sort($hours_array);

  if (!isFrench()) {
    return date('g:ia', strtotime($hours_array[0]));
  } else {
    return french_time_format(date('h:ia', strtotime($hours_array[0])));
  }
}

function get_max_open_today($day)
{
  $hours = get_dealer_hours();
  $hours_additional_settings = get_dealer_hours_additional();
  $sale_hours = $hours["sale"];
  $service_hours = $hours["service"];
  $parts_hours = $hours["parts"];
  $exploded_time = explode('-', str_replace(' ', '', $sale_hours[ucfirst($day)]));
  $exploded_time_service = explode('-', str_replace(' ', '', $service_hours[ucfirst($day)]));
  $exploded_time_parts = explode('-', str_replace(' ', '', $parts_hours[ucfirst($day)]));
  $hours_array = [];

  if ($exploded_time[0] != 'Closed') {
    array_push($hours_array, date("H:i", strtotime($exploded_time[1])));
  }
  if ($exploded_time_service[0] != 'Closed' && $hours_additional_settings['servicehourstatus'] == 'Enabled') {
    array_push($hours_array, date("H:i", strtotime($exploded_time_service[1])));
  }
  if ($exploded_time_parts[0] != 'Closed' && $hours_additional_settings['parthourstatus'] == 'Enabled') {
    array_push($hours_array, date("H:i", strtotime($exploded_time_parts[1])));
  }

  if (count($hours_array) == 0)
    return 'Closed';

  rsort($hours_array);

  if (!isFrench()) {
    return date('g:ia', strtotime($hours_array[0]));
  } else {
    return french_time_format(date('h:ia', strtotime($hours_array[0])));
  }
}


/* GET FORD ADOBE TAGGING */
function show_ford_adobe_tagging()
{
  $show = false;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["ford_adobe_option"])
    && !empty($lbSettings["ford_adobe_option"]) && (strtolower($lbSettings["ford_adobe_option"]) == "enabled")
  ) {
    $show = true;
  }

  return $show;
}

/* SHOW MODEL E PRICE */
function show_model_e_setting()
{
  $show = false;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["model_e_setting"])
    && !empty($lbSettings["model_e_setting"]) && (strtolower($lbSettings["model_e_setting"]) == "enabled")
  ) {
    $show = true;
  }

  return $show;
}

/* GET FORD DEALER CODE */
function get_ford_dealer_code()
{
  $dealer_code = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["ford_dealer_code"])
    && !empty($lbSettings["ford_dealer_code"]) && (strlen($lbSettings["ford_dealer_code"]) > 0)
  ) {
    $dealer_code = $lbSettings["ford_dealer_code"];
  }

  return $dealer_code;
}

function get_graphql_url()
{
  $graphql_url = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["graphql_url"])
    && !empty($lbSettings["graphql_url"]) && (strlen($lbSettings["graphql_url"]) > 0)
  ) {
    $graphql_url = $lbSettings["graphql_url"];
  }

  return $graphql_url;
}

function get_live_agent_option()
{
  $dealer_code = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["live_agent"])
    && !empty($lbSettings["live_agent"]) && (strlen($lbSettings["live_agent"]) > 0)
  ) {
    $dealer_code = $lbSettings["live_agent"];
  }

  return $dealer_code;
}

function get_live_agent_code()
{
  $dealer_code = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["live_agent_code"])
    && !empty($lbSettings["live_agent_code"]) && (strlen($lbSettings["live_agent_code"]) > 0)
  ) {
    $dealer_code = $lbSettings["live_agent_code"];
  }

  return $dealer_code;
}

function get_moto_insight_option()
{
  $option = "disabled";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["moto_insight"])
    && !empty($lbSettings["moto_insight"]) && (strlen($lbSettings["moto_insight"]) > 0)
  ) {
    $option = strtolower($lbSettings["moto_insight"]);
  }

  return $option;
}

function get_moto_insight_url()
{
  $dealer_input = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["moto_insight_url"])
    && !empty($lbSettings["moto_insight_url"]) && (strlen($lbSettings["moto_insight_url"]) > 0)
  ) {
    $dealer_input = $lbSettings["moto_insight_url"];
  }
  return $dealer_input;
}

function show_moto_insight_button()
{
  if (get_moto_insight_option() == 'enabled' && get_moto_insight_url() != '') {
    return true;
  } else {
    return false;
  }
}

function get_moto_insight_label()
{
  $dealer_input = "BUILD YOUR DEAL";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["moto_insight_label"])
    && !empty($lbSettings["moto_insight_label"]) && (strlen($lbSettings["moto_insight_label"]) > 0)
  ) {
    $dealer_input = $lbSettings["moto_insight_label"];
  }

  return $dealer_input;

}

function get_moto_insight_label_fr()
{
  $dealer_input = "CONSTRUISEZ VOTRE OFFRE";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["moto_insight_label_fr"])
    && !empty($lbSettings["moto_insight_label_fr"]) && (strlen($lbSettings["moto_insight_label_fr"]) > 0)
  ) {
    $dealer_input = $lbSettings["moto_insight_label_fr"];
  }
  return $dealer_input;
}

function get_carfax_option()
{
  $option = "disabled";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["carfax"])
    && !empty($lbSettings["carfax"]) && (strlen($lbSettings["carfax"]) > 0)
  ) {
    $option = strtolower($lbSettings["carfax"]);
  }

  return $option;
}


function get_cartender_option()
{
  $option = "disabled";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["cartender"])
    && !empty($lbSettings["cartender"]) && (strlen($lbSettings["cartender"]) > 0)
  ) {
    $option = strtolower($lbSettings["cartender"]);
  }

  return $option;
}

function get_cartender_url()
{
  $dealer_input = null;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["cartender_url"])
    && !empty($lbSettings["cartender_url"]) && (strlen($lbSettings["cartender_url"]) > 0)
  ) {
    $dealer_input = $lbSettings["cartender_url"];
  }
  return $dealer_input;
}

function show_cartender_button()
{
  if (get_cartender_option() == 'enabled' && get_cartender_url() != '') {
    return true;
  } else {
    return false;
  }
}

function get_cartender_label()
{
  $dealer_input = "VIDEO OVERVIEW";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["cartender_label"])
    && !empty($lbSettings["cartender_label"]) && (strlen($lbSettings["cartender_label"]) > 0)
  ) {
    $dealer_input = $lbSettings["cartender_label"];
  }

  return $dealer_input;

}

function get_cartender_label_fr()
{
  $dealer_input = "VIDEO OVERVIEW";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["cartender_label_fr"])
    && !empty($lbSettings["cartender_label_fr"]) && (strlen($lbSettings["cartender_label_fr"]) > 0)
  ) {
    $dealer_input = $lbSettings["cartender_label_fr"];
  }
  return $dealer_input;
}

const LBX_ADOBE_JSON = <<<'JSON'
[
  {
    "nonvehicle": [
      {
        "pagename": "dc:specials:offers:contact us:thank you",
        "channel": "specials",
        "hier": "specials",
        "pagenamenovehicle": "dc:specials:offers:contact us:thank you",
        "slugs": "contact-us-specials-offers,contact-specials-offers,specials-offers",
        "tool": "default form",
        "tooldescriptor": "offers:contact",
        "leadtype": "offers:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:specials:new specials:contact us:thank you",
        "channel": "specials",
        "hier": "specials",
        "pagenamenovehicle": "dc:specials:new specials:contact us:thank you",
        "slugs": "contact-us-new-specials,contact-new-specials,new-specials",
        "tool": "default form",
        "tooldescriptor": "new specials:contact",
        "leadtype": "new specials:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:specials:used specials:contact us:thank you",
        "channel": "specials",
        "hier": "specials",
        "pagenamenovehicle": "dc:specials:used specials:contact us:thank you",
        "slugs": "contact-us-used-specials,contact-used-specials,used-specials",
        "tool": "default form",
        "tooldescriptor": "used specials:contact",
        "leadtype": "used specials:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:specials:finance:contact us:thank you",
        "channel": "specials",
        "hier": "specials",
        "pagenamenovehicle": "dc:specials:finance:contact us:thank you",
        "slugs": "contact-us-finance,contact-finance,finance",
        "tool": "default form",
        "tooldescriptor": "finance:contact",
        "leadtype": "finance:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:specials:service:contact us:thank you",
        "channel": "specials",
        "hier": "specials",
        "pagenamenovehicle": "dc:specials:service:contact us:thank you",
        "slugs": "contact-us-specials-service,contact-us-service-specials,contact-specials-service,specials-service",
        "tool": "default form",
        "tooldescriptor": "service:contact",
        "leadtype": "service:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:specials:parts:contact us:thank you",
        "channel": "specials",
        "hier": "specials",
        "pagenamenovehicle": "dc:specials:parts:contact us:thank you",
        "slugs": "contact-us-specials-parts,contact-us-parts-specials,contact-specials-parts,specials-parts",
        "tool": "default form",
        "tooldescriptor": "parts:contact",
        "leadtype": "parts:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:service:request appointment:thank you",
        "channel": "service and parts",
        "hier": "service and parts:request appointment",
        "pagenamenovehicle": "dc:service:request appointment:thank you",
        "slugs": "book-an-appointment,book-appointment,service,request-appointment,schedule-service,book-a-service-appointment,service-appointment",
        "tool": "default form",
        "tooldescriptor": "request appointment",
        "leadtype": "request appointment",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:service:order parts:contact us:thank you",
        "channel": "service and parts",
        "hier": "service and parts:order parts",
        "pagenamenovehicle": "dc:service:order parts:contact us:thank you",
        "slugs": "parts,contact-us-service-order-parts,order-parts",
        "tool": "default form",
        "tooldescriptor": "order parts:contact",
        "leadtype": "order parts:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:service:accessories:contact us:thank you",
        "channel": "service and parts",
        "hier": "service and parts:accessories",
        "pagenamenovehicle": "dc:service:accessories:contact us:thank you",
        "slugs": "accessories,contact-us-service-accessories,service-accessories,order-accessories",
        "tool": "default form",
        "tooldescriptor": "accessories:contact",
        "leadtype": "accessories:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:ev lifestyle:test drive:thank you",
        "channel": "ev landing page",
        "hier": "shopping tools:ev lifestyle:test drive",
        "pagenamenovehicle": "dc:ev lifestyle:test drive:thank you",
        "slugs": "ev-lifestyle-test-drive-thank-you",
        "tool": "event:lead submitted",
        "tooldescriptor": "ev lifestyle:test drive",
        "leadtype": "ev ownership:test drive:thank you",
        "variantname": "test-drive-submit",
        "action": "lead submitted|test drive|tool"
      },
      {
        "pagename": "dc:ev ownership:contact us:thank you",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership:contact us:thank you",
        "slugs": "ev-ownership-contact-us-thank-you",
        "tool": "ev ownership:contact us",
        "tooldescriptor": "ev ownership:contact us",
        "leadtype": "ev ownership:contact us",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:ev lifestyle:contact us:thank you",
        "channel": "ev landing page",
        "hier": "ev lifestyle",
        "pagenamenovehicle": "dc:ev lifestyle:contact us:thank you",
        "slugs": "ev-lifestyle-contact-us-thank-you",
        "tool": "ev lifestyle:contact us",
        "tooldescriptor": "ev lifestyle:contact us",
        "leadtype": "ev lifestyle:contact us",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:ev vhp:contact us:thank you",
        "channel": "ev vhp",
        "hier": "shopping tools:ev vhp:contact us",
        "pagenamenovehicle": "dc:ev vhp:contact us:thank you",
        "slugs": "ev-vhp-contact-us-thank-you",
        "tool": "ev vhp:contact us",
        "tooldescriptor": "ev vhp:contact",
        "leadtype": "ev vhp:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:about us:thank you",
        "channel": "about us",
        "hier": "about us",
        "pagenamenovehicle": "dc:about us:thank you",
        "slugs": "about-us,contact-about-us,contact-us-about-us",
        "tool": "default form",
        "tooldescriptor": "about us:contact",
        "leadtype": "about us:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:about us:contact us:thank you",
        "channel": "about us",
        "hier": "about us:contact us",
        "pagenamenovehicle": "dc:about us:contact us:thank you",
        "slugs": "contact,contact-us",
        "tool": "default form",
        "tooldescriptor": "contact us:contact",
        "leadtype": "contact us:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:about us:careers:contact us:thank you",
        "channel": "about us",
        "hier": "about us:careers",
        "pagenamenovehicle": "dc:about us:careers:contact us:thank you",
        "slugs": "contact-us-careers,careers",
        "tool": "default form",
        "tooldescriptor": "careers:contact",
        "leadtype": "careers:contact",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      },
      {
        "pagename": "dc:test drive:thank you",
        "channel": "test drive",
        "hier": "shopping tools:test drive",
        "pagenamenovehicle": "dc:test drive:thank you",
        "slugs": "test-drive,schedule-test-drive,book-test-drive,test-drive-no-vehicle,book-a-test-drive-no-vehicle",
        "tool": "event:lead submitted",
        "tooldescriptor": "test drive",
        "leadtype": "test drive",
        "variantname": "test-drive-submit",
        "action": "lead submitted|test drive|tool"
      },
      {
        "pagename": "dc:value your trade:thank you",
        "channel": "search inventory",
        "hier": "shopping tools:value your trade",
        "pagenamenovehicle": "dc:value your trade:thank you",
        "slugs": "trade-in,trade-in-value,trade-in-appraisal,value-your-trade,trade-in-appraisal-no-vehicle,value-your-trade-no-vehicle",
        "tool": "event:value your trade",
        "tooldescriptor": "vehicle details:value your trade",
        "leadtype": "vdp:value your trade",
        "variantname": "vrmi-submit",
        "action": "lead submitted|vehicle quote|tool"
      },
      {
        "pagename": "dc:ev ownership:get updates:thank you",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership:get updates:thank you",
        "slugs": "ev-ownership-get-updates",
        "tool": "ev ownership:get updates",
        "tooldescriptor": "ev ownership:get updates",
        "leadtype": "ev ownership:get updates",
        "variantname": "form-submit",
        "action": "lead submitted|tool"
      }
    ],
    "vehicle": [
      {
        "pagename": "dc:{new|used|cpo}:si:vehicle details:test drive:thank you:<nameplate>",
        "channel": "test drive",
        "hier": "shopping tools:test drive:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vehicle details:test drive:thank you",
        "slugs": "test-drive,book-a-test-drive",
        "tool": "event:lead submitted",
        "tooldescriptor": "vehicle details:test drive",
        "leadtype": "vdp:test drive",
        "variantname": "test-drive-submit",
        "action": "lead submitted|test drive|tool"
      },
      {
        "pagename": "dc:home:vrmi:thank you:<nameplate>",
        "channel": "home",
        "hier": "home:<model year>:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:home:vrmi:thank you",
        "slugs": "vrmi-home",
        "tool": "event:vrmi",
        "tooldescriptor": "home:vrmi",
        "leadtype": "home:vrmi",
        "variantname": "value-your-trade-submit",
        "action": "lead submitted|appraisals|tool"
      },
      {
        "pagename": "dc:{new|used|cpo}:si:vls:vrmi:thank you:<nameplate>",
        "channel": "get quote",
        "hier": "shopping tools:get quote:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vls:vrmi:thank you",
        "slugs": "get-quote,quick-quote",
        "tool": "event:get quote",
        "tooldescriptor": "search inventory:get quote",
        "leadtype": "si:vrmi",
        "variantname": "value-your-trade-submit",
        "action": "lead submitted|appraisals|tool"
      },
      {
        "pagename": "dc:{new|used|cpo}:si:vehicle details:vrmi:thank you:<nameplate>",
        "channel": "get quote",
        "hier": "shopping tools:get quote:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vehicle details:vrmi:thank you",
        "slugs": "request-information,request-more-information,get-quote,quick-quote",
        "tool": "event:get quote",
        "tooldescriptor": "vehicle details:get quote",
        "leadtype": "vdp:vrmi",
        "variantname": "vrmi-submit",
        "action": "lead submitted|appraisals|tool"
      },
      {
        "pagename": "dc:{new|used|cpo}:si:vehicle details:value your trade:thank you:<nameplate>",
        "channel": "search inventory",
        "hier": "shopping tools:value your trade:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vehicle details:value your trade:thank you",
        "slugs": "trade-in-appraisal,value-your-trade",
        "tool": "event:value your trade",
        "tooldescriptor": "vehicle details:value your trade",
        "leadtype": "vdp:value your trade",
        "variantname": "vrmi-submit",
        "action": "lead submitted|vehicle quote|tool"
      }
    ],
    "vls": [
      {
        "pagename": "dc:{new|used|cpo}:si:vls:vrmi:thank you:<nameplate>",
        "channel": "get quote",
        "hier": "shopping tools:get quote:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vls:vrmi:thank you",
        "slugs": "request-information,request-more-information",
        "tool": "event:get quote",
        "tooldescriptor": "search inventory:get quote",
        "leadtype": "si:vrmi",
        "variantname": "vrmi-submit",
        "action": "lead submitted|appraisals|tool"
      }
    ],
    "home-vrmi": [
      {
        "pagename": "dc:home:vrmi:thank you:<nameplate>",
        "channel": "home",
        "hier": "home:<model year>:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:home:vrmi:thank you",
        "slugs": "home,request-information,request-more-information,ask-a-question,ask-question",
        "tool": "event:vrmi",
        "tooldescriptor": "home:vrmi",
        "leadtype": "home:vrmi",
        "variantname": "vrmi-submit",
        "action": "lead submitted|appraisals|tool"
      }
    ],
    "pages": [
      {
        "pagename": "dc:ev lifestyle:test drive:thank you",
        "channel": "ev landing page",
        "hier": "shopping tools:ev lifestyle:test drive",
        "pagenamenovehicle": "dc:ev lifestyle:test drive:thank you",
        "slugs": "ev-lifestyle-test-drive-thank-you",
        "tool": "event:lead submitted",
        "tooldescriptor": "ev lifestyle:test drive",
        "leadtype": "ev ownership:test drive:thank you",
        "variantname": "test-drive-submit",
        "action": "lead submitted|test drive|tool"
      },
      {
        "pagename": "dc:ev ownership:contact us:thank you",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership:contact us:thank you",
        "slugs": "ev-ownership-contact-us-thank-you"
      },
      {
        "pagename": "dc:ev vhp:contact us:thank you",
        "channel": "ev vhp",
        "hier": "shopping tools:ev vhp:contact us",
        "pagenamenovehicle": "dc:ev vhp:contact us:thank you",
        "slugs": "ev-vhp-contact-us-thank-you"
      },
      {
        "pagename": "dc:ev ownership:contact us",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership:contact us",
        "slugs": "ev-ownership-contact-us,contact-us-ev-ownership"
      },
      {
        "pagename": "dc:home",
        "channel": "home",
        "hier": "home",
        "pagenamenovehicle": "dc:home",
        "slugs": "home,welcome"
      },
      {
        "pagename": "dc:help:privacy",
        "channel": "help",
        "hier": "help:privacy",
        "pagenamenovehicle": "dc:help:privacy",
        "slugs": "privacy"
      },
      {
        "pagename": "dc:help:disclosures",
        "channel": "help",
        "hier": "help:disclosures",
        "pagenamenovehicle": "dc:help:disclosures",
        "slugs": "disclosures,terms-conditions"
      },
      {
        "pagename": "dc:cpo overview",
        "channel": "cpo overview",
        "hier": "cpo overview",
        "pagenamenovehicle": "dc:cpo overview",
        "slugs": "cpo-overview"
      },
      {
        "pagename": "dc:ford co pilot assist",
        "channel": "ford co pilot assist",
        "hier": "ford co pilot assist",
        "pagenamenovehicle": "dc:ford co pilot assist",
        "slugs": "ford-co-pilot,co-pilot-assist,ford-co-pilot-assist"
      },
      {
        "pagename": "dc:value your trade",
        "channel": "search inventory",
        "hier": "shopping tools:value your trade",
        "pagenamenovehicle": "dc:value your trade",
        "slugs": "trade-in-value,value-your-trade,trade-in-vehicle-appraisal,trade-in-appraisal"
      },
      {
        "pagename": "dc:test drive",
        "channel": "test drive",
        "hier": "shopping tools:test drive",
        "pagenamenovehicle": "dc:test drive",
        "slugs": "test-drive"
      },
      {
        "pagename": "dc:service:request appointment",
        "channel": "service and parts",
        "hier": "service and parts:request appointment",
        "pagenamenovehicle": "dc:service:request appointment",
        "slugs": "book-an-appointment,book-appointment,request-appointment,service-appointment,schedule-appointment,schedule-service"
      },
      {
        "pagename": "dc:service:service and parts",
        "channel": "service and parts",
        "hier": "service and parts",
        "pagenamenovehicle": "dc:service:service and parts",
        "slugs": "service,service-parts,service-department,parts-department"
      },
      {
        "pagename": "dc:service:order parts",
        "channel": "service and parts",
        "hier": "service and parts:order parts",
        "pagenamenovehicle": "dc:service:order parts",
        "slugs": "parts,order-parts"
      },
      {
        "pagename": "dc:service:quick lane",
        "channel": "service and parts",
        "hier": "service and parts:quick lane",
        "pagenamenovehicle": "dc:service:quick lane",
        "slugs": "quick-lane,quicklane"
      },
      {
        "pagename": "dc:service:accessories",
        "channel": "service and parts",
        "hier": "service and parts:accessories",
        "pagenamenovehicle": "dc:service:accessories",
        "slugs": "accessories"
      },
      {
        "pagename": "dc:service:extended warranty",
        "channel": "service and parts",
        "hier": "service and parts:extended warranty",
        "pagenamenovehicle": "dc:service:extended warranty",
        "slugs": "extended-warranty"
      },
      {
        "pagename": "dc:service:owner advantage rewards",
        "channel": "service and parts",
        "hier": "service and parts:owner advantage rewards",
        "pagenamenovehicle": "dc:service:owner advantage rewards",
        "slugs": "owner-advantage-rewards,advantage-rewards,owner-advantage"
      },
      {
        "pagename": "dc:service:fordpass",
        "channel": "service and parts",
        "hier": "service and parts:fordpass",
        "pagenamenovehicle": "dc:service:fordpass",
        "slugs": "fordpass"
      },
      {
        "pagename": "dc:ev ownership:contact us",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership:contact us",
        "slugs": "ev-ownership-contact-us"
      },
      {
        "pagename": "dc:ev lifestyle:contact us",
        "channel": "ev landing page",
        "hier": "ev lifestyle",
        "pagenamenovehicle": "dc:ev lifestyle:contact us",
        "slugs": "ev-lifestyle-contact-us"
      },
      {
        "pagename": "dc:ev lifestyle:test drive",
        "channel": "ev landing page",
        "hier": "ev lifestyle",
        "pagenamenovehicle": "dc:ev lifestyle:test drive",
        "slugs": "ev-lifestyle-test-drive"
      },
      {
        "pagename": "dc:ev vhp:test drive:thank you:<mach-e>",
        "channel": "ev vhp",
        "hier": "shopping tools:ev vhp:test drive:<mach-e>",
        "pagenamenovehicle": "dc:ev vhp:test drive:thank you",
        "slugs": "book-a-test-drive-mustang-mach-e-thank-you"
      },
      {
        "pagename": "dc:ev vhp:test drive:thank you:<F150 lightning>",
        "channel": "ev vhp",
        "hier": "shopping tools:ev vhp:test drive:<F150 lightning>",
        "pagenamenovehicle": "dc:ev vhp:test drive:thank you",
        "slugs": "book-a-test-drive-f-150-lightning-thank-you"
      },
      {
        "pagename": "dc:ev vhp:test drive",
        "channel": "ev vhp",
        "hier": "shopping tools:ev vhp:test drive",
        "pagenamenovehicle": "dc:ev vhp:test drive",
        "slugs": "book-a-test-drive-mustang-mach-e,book-a-test-drive-f-150-lightning"
      },
      {
        "pagename": "dc:ev charging:contact us",
        "channel": "ev landing page",
        "hier": "ev charging",
        "pagenamenovehicle": "dc:ev charging:contact us",
        "slugs": "ev-charging-contact-us"
      },
      {
        "pagename": "dc:ev vhp:contact us",
        "channel": "ev vhp",
        "hier": "shopping tools:ev vhp:contact us",
        "pagenamenovehicle": "dc:ev vhp:contact us",
        "slugs": "ev-vhp-contact-us"
      },
      {
        "pagename": "dc:about us",
        "channel": "about us",
        "hier": "about us",
        "pagenamenovehicle": "dc:about us",
        "slugs": "about-us"
      },
      {
        "pagename": "dc:about us:contact us",
        "channel": "about us",
        "hier": "about us:contact us",
        "pagenamenovehicle": "dc:about us:contact us",
        "slugs": "contact,contact-us"
      },
      {
        "pagename": "dc:about us:meet our staff",
        "channel": "about us",
        "hier": "about us:meet our staff",
        "pagenamenovehicle": "dc:about us:meet our staff",
        "slugs": "staff,team,our-staff,our-team,meet-our-staff,meet-our-team"
      },
      {
        "pagename": "dc:about us:community",
        "channel": "about us",
        "hier": "about us:community",
        "pagenamenovehicle": "dc:about us:community",
        "slugs": "community"
      },
      {
        "pagename": "dc:about us:careers",
        "channel": "about us",
        "hier": "about us:careers",
        "pagenamenovehicle": "dc:about us:careers",
        "slugs": "careers"
      },
      {
        "pagename": "dc:shopping tools:credit application",
        "channel": "shopping tools",
        "hier": "shopping tools",
        "pagenamenovehicle": "dc:shopping tools:credit application",
        "slugs": "credit-application,apply-credit,financing"
      },
      {
        "pagename": "dc:ev ownership:get updates",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership:get updates",
        "slugs": "ev-ownership-get-updates"
      },
      {
        "pagename": "dc:ev ownership",
        "channel": "ev ownership",
        "hier": "ev ownership",
        "pagenamenovehicle": "dc:ev ownership",
        "slugs": "ev-ownership"
      },
      {
        "pagename": "dc:ev charging",
        "channel": "ev landing page",
        "hier": "ev charging",
        "pagenamenovehicle": "dc:ev charging",
        "slugs": "ev-charging"
      },
      {
        "pagename": "dc:ev lifestyle",
        "channel": "ev landing page",
        "hier": "ev lifestyle",
        "pagenamenovehicle": "dc:ev lifestyle",
        "slugs": "ev-lifestyle"
      },
      {
        "pagename": "dc:ev vhp:ev mach-e",
        "channel": "ev vhp",
        "hier": "ev vhp",
        "pagenamenovehicle": "dc:ev vhp",
        "slugs": "ev-mach-e"
      },
      {
        "pagename": "dc:ev vhp:ev-lightning",
        "channel": "ev vhp",
        "hier": "ev vhp",
        "pagenamenovehicle": "dc:ev vhp",
        "slugs": "ev-lightning"
      }
    ],
    "formsrequestvls": [
      {
        "pagename": "dc:{new|used|cpo}:si:vls:vrmi:<nameplate>",
        "channel": "get quote",
        "hier": "shopping tools:get quote:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vls:vrmi",
        "slugs": "request-information,request-more-information,get-quote,quick-quote"
      }
    ],
    "formsrequestvdp": [
      {
        "pagename": "dc:{new|used|cpo}:si:vehicle details:vrmi:<nameplate>",
        "channel": "get quote",
        "hier": "shopping tools:get quote:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vehicle details:vrmi",
        "slugs": "request-information,request-more-information,get-quote,quick-quote"
      },
      {
        "pagename": "dc:{new|used|cpo}:si:vehicle details:test drive:<nameplate>",
        "channel": "test drive",
        "hier": "shopping tools:test drive:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vehicle details:test drive",
        "slugs": "test-drive,book-a-test-drive"
      },
      {
        "pagename": "dc:{new|used|cpo}:si:vehicle details:value your trade:<nameplate>",
        "channel": "search inventory",
        "hier": "shopping tools:value your trade:<vehicle category>:<nameplate>",
        "pagenamenovehicle": "dc:{new|used|cpo}:si:vehicle details:value your trade",
        "slugs": "trade-in-appraisal,value-your-trade"
      }
    ]
  }
]
JSON;

function lbx_get_adobe_data_array() {
  static $data = null;
  if ($data === null) {
    $data = json_decode(LBX_ADOBE_JSON, true);
    if (!is_array($data)) $data = [];
  }
  return $data;
}

if (!function_exists('adobe_contains_value')) {
  function adobe_contains_value($text, $words) {
    $array = explode("-", strtolower($words));
    $total_words = count($array);
    $vehicle = array_map('strtolower', explode('-', $text));
    $total_coincidences = 0;
    foreach ($array as $item) {
      $total_i = count(array_filter($vehicle, function ($var) use ($item) {
        return strpos($var, $item) !== false;
      }));
      $total_p = count(array_filter($vehicle, function ($var) use ($item) {
        return strpos(str_replace("-", "", $var), str_replace("-", " ", $item)) !== false;
      }));
      if ($total_i > 0 || $total_p)
        $total_coincidences++;
    }
    return $total_words == $total_coincidences;
  }
}

function get_adobe_data_from_slug($slug) {
  $adobeData = lbx_get_adobe_data_array();
  if (!empty($adobeData) && !empty($adobeData[0]['pages'])) {
    $slug_lower = strtolower(trim($slug));

    // Primero buscar coincidencia EXACTA
    foreach ($adobeData[0]['pages'] as $aData) {
      $slugs = array_map('trim', explode(',', $aData['slugs'] ?? ''));
      foreach ($slugs as $aSlug) {
        if ($aSlug !== '' && strtolower($aSlug) === $slug_lower) {
          return $aData;
        }
      }
    }

    // Si no hay coincidencia exacta, buscar coincidencia por palabras
    // (solo si tienen el mismo número de segmentos, para no matchear ej. ev-vhp-contact-us-thank-you con ev-vhp-contact-us)
    $slug_parts = count(explode('-', $slug_lower));
    foreach ($adobeData[0]['pages'] as $aData) {
      $slugs = array_map('trim', explode(',', $aData['slugs'] ?? ''));
      foreach ($slugs as $aSlug) {
        if ($aSlug !== '' && count(explode('-', strtolower($aSlug))) === $slug_parts && adobe_contains_value($slug, $aSlug)) {
          return $aData;
        }
      }
    }
  }
  return null;
}

function get_adobe_forms_data_from_slug($slug, $veh = 'nonvehicle') {
  $adobeData = lbx_get_adobe_data_array();
  if (empty($adobeData)) return null;

  // Selección del bloque
  $key = in_array($veh, ['home-vrmi','vls','nonvehicle','vehicle'], true) ? $veh : 'nonvehicle';
  $items = $adobeData[0][$key] ?? [];
  $slug_lower = strtolower(trim($slug));

  // Primero coincidencia exacta
  foreach ($items as $aData) {
    $slugs = array_map('trim', explode(',', $aData['slugs'] ?? ''));
    foreach ($slugs as $aSlug) {
      if ($aSlug !== '' && strtolower($aSlug) === $slug_lower) {
        return $aData;
      }
    }
  }

  // Luego coincidencia por palabras
  foreach ($items as $aData) {
    $slugs = array_map('trim', explode(',', $aData['slugs'] ?? ''));
    foreach ($slugs as $aSlug) {
      if ($aSlug !== '' && adobe_contains_value($slug, $aSlug)) {
        return $aData;
      }
    }
  }
  return null;
}

/* GET OEM PROGRAM */
function get_oem_program()
{
    $oem_program = "leadbox";
    $lbSettings = get_leadbox_settings();
    if (
        isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["oem_program"])
        && !empty($lbSettings["oem_program"]) && (strlen($lbSettings["oem_program"]) > 0)
    ) {
        $oem_program = strtolower($lbSettings["oem_program"]);
    }

    return $oem_program;
}

/* GET JLR ENVIRONMENT */
function get_jlr_environment()
{
  $environment = "staging";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["jlr_version"])
    && !empty($lbSettings["jlr_version"]) && (strlen($lbSettings["jlr_version"]) > 0)
  ) {
    $environment = strtolower($lbSettings["jlr_version"]);
  }

  return $environment;
}

/* GET JLR TAGGING */
function show_jlr_tagging()
{
  $show = false;
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["jlr_option"])
    && !empty($lbSettings["jlr_option"]) && (strtolower($lbSettings["jlr_option"]) == "enabled")
  ) {
    $show = true;
  }

  return $show;
}

function jlr_contains_value($text, $words)
{
  $array = explode("-", strtolower($words));
  $total_words = count($array);
  $vehicle = array_map('strtolower', explode('-', $text));
  $total_coincidences = 0;
  foreach ($array as $item) {
    $total_i = count(array_filter($vehicle, function ($var) use ($item) {
      return strpos($var, $item) !== false;
    }));
    $total_p = count(array_filter($vehicle, function ($var) use ($item) {
      return strpos(str_replace("-", "", $var), str_replace("-", " ", $item)) !== false;
    }));
    if ($total_i > 0 || $total_p)
      $total_coincidences++;
  }

  if ($total_words == $total_coincidences) {
    return true;
  } else {
    return false;
  }
}

const LBX_JLR_JSON = <<<JSON
[
  {
    "forms": [
      {
        "formtype": "Get a Quote",
        "coincidences": "get-a-quick-quote"
      },
      {
        "formtype": "Test Drive",
        "coincidences": "test-drive, book-a-test-drive"
      },
      {
        "formtype": "Request More Info",
        "coincidences": "request-more-information, request-more-info,confirm-availability,check-availability"
      },
      {
        "formtype": "email a Friend",
        "coincidences": "email-a-friend"
      },
      {
        "formtype": "General Contact",
        "coincidences": "contact, contact-us"
      },
      {
        "formtype": "Service",
        "coincidences": "service"
      },
      {
        "formtype": "Parts",
        "coincidences": "parts, request-parts"
      },
      {
        "formtype": "Schedule Service",
        "coincidences": "schedule-service, service-appointment,book-an-appointment"
      },
      {
        "formtype": "Employment",
        "coincidences": "employment, job-opportunities, employment-opportunities"
      },
      {
        "formtype": "Trade In",
        "coincidences": "trade-in, trade-in-appraisal, trade-in-value"
      },
      {
        "formtype": "Finance",
        "coincidences": "finance,financing"
      },
      {
        "formtype": "Payment Estimator",
        "coincidences": "payment-estimator, payment-calculator"
      },
      {
        "formtype": "Specials",
        "coincidences": "specials"
      },
      {
        "formtype": "Vehicle Finder",
        "coincidences": "vehicle-finder"
      },
      {
        "formtype": "Dealer Custom",
        "coincidences": "dealer-custom"
      },
      {
        "formtype": "Make an Offer",
        "coincidences": "make-an-offer"
      },
      {
        "formtype": "Send to Mobile",
        "coincidences": "send-to-mobile"
      },
      {
        "formtype": "Other",
        "coincidences": "other"
      }
    ]
  }
]
JSON;

const LBX_JLR_PAGE_TYPES_JSON = <<<JSON
[
  {
    "pages": [
      {
        "pagename": "Home",
        "coincidences": "Home, homepage"
      },
      {
        "pagename": "Model Showroom",
        "coincidences": "model-showroom, showroom"
      },
      {
        "pagename": "Brochure",
        "coincidences": "Brochure"
      },
      {
        "pagename": "Trade In",
        "coincidences": "trade-in-value,trade-in-appraisal"
      },
      {
        "pagename": "Vehicle Listing",
        "coincidences": "new-inventory, used-inventory"
      },
      {
        "pagename": "Vehicle Details",
        "coincidences": "view"
      },
      {
        "pagename": "Test Drive",
        "coincidences": "schedule-a-test-drive, test-drive"
      },
      {
        "pagename": "Dealer Specials",
        "coincidences": "new-vehicle-specials, used-vehicle-specials, specials"
      },
      {
        "pagename": "OEM Incentives",
        "coincidences": "oem-incentives"
      },
      {
        "pagename": "Special Offers",
        "coincidences": "gm-special-offers"
      },
      {
        "pagename": "Service Specials",
        "coincidences": "service-specials"
      },
      {
        "pagename": "CPOV Program",
        "coincidences": "cpov-program"
      },
      {
        "pagename": "Finance",
        "coincidences": "finance, financing"
      },
      {
        "pagename": "Finance Prequalification",
        "coincidences": "finance-prequalification"
      },
      {
        "pagename": "Service",
        "coincidences": "service"
      },
      {
        "pagename": "Schedule Service",
        "coincidences": "schedule-service,book-an-appointment"
      },
      {
        "pagename": "Tire Store",
        "coincidences": "tire-store,tire-centre"
      },
      {
        "pagename": "Parts",
        "coincidences": "order-parts, parts"
      },
      {
        "pagename": "Accessories",
        "coincidences": "accessories"
      },
      {
        "pagename": "About Us",
        "coincidences": "about-us"
      },
      {
        "pagename": "Hours & Directions",
        "coincidences": "hours-and-directions"
      },
      {
        "pagename": "Contact Us",
        "coincidences": "contact-us"
      },
      {
        "pagename": "Custom Dealer Content",
        "coincidences": "custom-dealer-content"
      },
      {
        "pagename": "Fleet",
        "coincidences": "fleet-commercial"
      },
      {
        "pagename": "Other",
        "coincidences": "other"
      },
      {
        "pagename": "Blog",
        "coincidences": "blog"
      },
      {
        "pagename": "Business Elite",
        "coincidences": "business-elite"
      },
      {
        "pagename": "Onstar",
        "coincidences": "onstar"
      },
      {
        "pagename": "Service Home",
        "coincidences": "service-home"
      },
      {
        "pagename": "Parts Home",
        "coincidences": "parts-home"
      },
      {
        "pagename": "Parts Order Form",
        "coincidences": "order-parts"
      },
      {
        "pagename": "Parts Specials",
        "coincidences": "parts-specials, special-parts"
      },
      {
        "pagename": "Service Specials",
        "coincidences": "service-specials, special-service"
      },
      {
        "pagename": "Accessories Home",
        "coincidences": "accessories-home"
      },
      {
        "pagename": "DriverGear",
        "coincidences": "drivergear"
      },
      {
        "pagename": "Service Event",
        "coincidences": "service-event"
      },
      {
        "pagename": "Maintenance Menu",
        "coincidences": "maintenance-menu"
      },
      {
        "pagename": "VW Care Maintenance",
        "coincidences": "vw-care-maintenance"
      },
      {
        "pagename": "Service Xpress",
        "coincidences": "service-xpress"
      },
      {
        "pagename": "Service Credit Card",
        "coincidences": "service-credit-card"
      },
      {
        "pagename": "Competitive Advantage",
        "coincidences": "competitive-advantage"
      }
    ]
  }
]
JSON;

function lbx_get_jlr_data_array() {
  static $data = null;
  if ($data === null) {
    $data = json_decode(LBX_JLR_JSON, true);
    if (!is_array($data)) $data = [];
  }
  return $data;
}

function lbx_get_jlr_page_types_data_array() {
  static $data = null;
  if ($data === null) {
    $data = json_decode(LBX_JLR_PAGE_TYPES_JSON, true);
    if (!is_array($data)) $data = [];
  }
  return $data;
}

function get_jlr_data_from_slug($slug, $checkForm = false)
{
  if ($checkForm) {
    $jlrData = lbx_get_jlr_data_array();

    if (isset($jlrData)) {
      foreach ($jlrData[0]["forms"] as $jData) {
        $coincidences = explode(",", $jData["coincidences"]);
        foreach ($coincidences as $coincidence) {
          if (jlr_contains_value(trim($slug), trim($coincidence))) {
            return $jData;
          }
        }
      }
    }
    return ["formtype" => "Other"];
  } else {
    $jlrData = lbx_get_jlr_page_types_data_array();

    if (isset($jlrData)) {
      foreach ($jlrData[0]["pages"] as $jData) {
        $coincidences = explode(",", $jData["coincidences"]);
        foreach ($coincidences as $coincidence) {
          if (jlr_contains_value(trim($slug), trim($coincidence))) {
            return $jData;
          }
        }
      }
    }

    return ["pagename" => "Other"];
  }
}

/* GET FORD ADOBE ENVIRONMENT */
function get_ford_adobe_environment()
{
  $environment = "staging";
  $lbSettings = get_leadbox_settings();
  if (
    isset($lbSettings) && !empty($lbSettings) && isset($lbSettings["ford_adobe_version"])
    && !empty($lbSettings["ford_adobe_version"]) && (strlen($lbSettings["ford_adobe_version"]) > 0)
  ) {
    $environment = strtolower($lbSettings["ford_adobe_version"]);
  }

  return $environment;
}

/* GET GENERAL ADOBE VALUES */
function get_general_adobe_values($post, $from, $vehicle_id)
{
  // Manifest requests are erroring due to lack of get_post()
  $post = $post ?? get_post();
  if (is_null($post)) {
    return [
      'pagename' => null,
      'channel' => null,
      'hier' => null,
      'pagenamenovehicle' => null,
    ];
  }

  $slug = $post->post_name;
  $title = $post->post_title;
  $home = is_front_page() || is_home();
  $adobe_value = [];
  if (isset($vehicle_id))
    $data = get_vehicle_by_id($vehicle_id);
  else
    $data = [];

  if ($home || strtolower($slug) == "home") {
    $adobe_value["pagename"] = htmlspecialchars("dc:home", ENT_QUOTES);
    $adobe_value["channel"] = "home";
    $adobe_value["hier"] = "home";
    $adobe_value["pagenamenovehicle"] = htmlspecialchars("dc:home", ENT_QUOTES);
  } else {
    if ((isset($from) && !empty($from)) || (isset($data) && !empty($data))) {
      $adobe_value = get_adobe_forms_data_from_slug($slug, (isset($from) && strlen($from) > 0) ? 'vls' : ((isset($data) && count($data) > 0) ? 'vehicle' : 'nonvehicle'));
      // Páginas thank-you y otras de formulario están en nonvehicle; si no hubo match, intentar nonvehicle
      if (!isset($adobe_value) || empty($adobe_value)) {
        $adobe_value = get_adobe_forms_data_from_slug($slug, 'nonvehicle');
      }
    } else {
      $adobe_value = get_adobe_forms_data_from_slug($slug, 'nonvehicle');
      if (!isset($adobe_value) || empty($adobe_value)) {
        $adobe_value = get_adobe_data_from_slug($slug);
      }
    }

    if (!has_block('leadbox/inventory-block', $post) && !isset($adobe_value)) {
      $adobe_value["pagename"] = htmlspecialchars("dc:custom:" . strtolower($title), ENT_QUOTES);
      $adobe_value["channel"] = "custom";
      $adobe_value["hier"] = "custom";
      $adobe_value["pagenamenovehicle"] = htmlspecialchars("dc:custom:" . strtolower($title), ENT_QUOTES);
    }
  }

  return $adobe_value;
}

function get_leadbox_manufacturer()
{
  $lbsettings = get_option('leadbox-settings');
  if (isset($lbsettings) && !empty($lbsettings) && isset($lbsettings["manufacturer"]) && !empty($lbsettings["manufacturer"])) {
    return strtolower(trim($lbsettings["manufacturer"]));
  } else {
    return "";
  }
}

function getYoutubeEmbedUrl($url)
{
  $rx = '~^(?:https?://)?(?:www[.])?(?:youtube[.]com/watch[?]v=|youtu[.]be/)([^&]{11})~x';

  if (preg_match($rx, $url, $matches)) {
    $youtube_id = $matches[count($matches) - 1];
  }
  return 'https://www.youtube.com/embed/' . $youtube_id;
}

function vdp_key($car_id, $date) {
  return "vdp:{$car_id}:{$date}";
}

function vdp_record_view_transient($car_id) {
  $car_id = (int) $car_id;
  if ($car_id <= 0) return;

  $today = current_time('Y-m-d');
  $key = vdp_key($car_id, $today);

  $count = get_transient($key);
  if ($count === false) { $count = 0; }
  $count++;
  // guarda por 8 días para poder sumar últimos 7 con margen
  set_transient($key, $count, DAY_IN_SECONDS * 8);

  wp_cache_delete("vdp7d:$car_id", 'vdp');
}

function vdp_get_7d_count_transient($car_id) {
  $car_id = (int) $car_id;
  if ($car_id <= 0) return 0;

  $cached = wp_cache_get("vdp7d:$car_id", 'vdp');
  if ($cached !== false) {
    return (int)$cached;
  }

  $sum = 0;
  for ($i = 0; $i < 7; $i++) {
    $date = date('Y-m-d', strtotime(current_time('Y-m-d') . " -$i days"));
    $sum += (int) (get_transient(vdp_key($car_id, $date)) ?: 0);
  }

  wp_cache_set("vdp7d:$car_id", $sum, 'vdp', MINUTE_IN_SECONDS * 10);
  return $sum;
}

function setVdpCountCar($id) {
  vdp_record_view_transient($id);
}

function getVdpCountCar($id) {
  return vdp_get_7d_count_transient($id);
}


function isKinstaUrl()
{
  $actual_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
  if (strpos($actual_link, 'kinsta') !== false && strpos($actual_link, 'cloud') !== false) {
    //var_dump($actual_link);
    if (strpos($actual_link, 'leadboxegyptqa') !== false) {
      return false;
    } else
      return true;
  }
}

function get_upgrade_name($name)
{
  switch ($name) {
    case 'G-1':
      return 'One Owner';
      break;

    case 'G-2':
      return 'Clean Carproof';
      break;

    case 'G-3':
      return 'In Demand Color';
      break;

    case 'G-4':
      return 'Low Kms';
      break;

    case 'G-5':
      return 'New Brakes';
      break;

    case 'G-6':
      return 'New Tires';
      break;

    case 'G-7':
      return 'Oil Change';
      break;

    case 'G-8':
      return 'New Wiper Blades';
      break;

    case 'G-9':
      return 'New Air Filter';
      break;

    case 'G-10':
      return 'Mpi Certified';
      break;

    case 'G-11':
      return 'Vehicle Detailed';
      break;

    case 'G-12':
      return 'New Arrival';
      break;

    default:
      return '';
      break;
  }
}

function get_compare_add_url($lang = 'en')
{
  $view = 'recherche';
  if (strpos($lang, 'en') !== false) {
    $view = 'search';
  }
  //$vehicle = get_vehicle_by_id($id);
  return "/" . $view;
}

function get_local_line_up()
{
  $route = '/resources/config/line-up.json';
  $jsonPath = get_fileInGenius($route);
  if (file_exists($jsonPath . $route)) {
    return json_decode(file_get_contents($jsonPath . $route), true);
  } else {
    return null;
  }
}

function get_local_used_line_up()
{
  $route = '/resources/config/used-line-up.json';
  $jsonPath = get_fileInGenius($route);
  if (file_exists($jsonPath . $route)) {
    return json_decode(file_get_contents($jsonPath . $route), true);
  } else {
    return null;
  }
}

function enqueueIsolatedScript($name, $lib = null){
  $theme_version = 0;

  // Check if theme activated is child or parent
  if (get_stylesheet() !== get_template())
    $theme_version = wp_get_theme()->parent()->get('Version');
  else
    $theme_version = wp_get_theme()->get('Version');

  $wp_scripts = wp_scripts();

  if(! in_array("genius/isolated/{$name}", $wp_scripts->queue)) {
    // Removed complicated lookup
    $file = get_theme_file_uri("/public/scripts/isolated/{$name}.js");
    wp_register_script("genius/isolated/{$name}", $file, [], $theme_version);
    wp_enqueue_script("genius/isolated/{$name}", $lib, ['sage/vendor.js', 'sage/app.js'], null, true);
  }
}

function mileage_format($n)
{
  return (number_format(floatval($n), 0));
}

function createCarfaxBadge($vin, $accountNumber, $WebServiceToken)
{
  $badge = "";

  if (!$WebServiceToken)
    $WebServiceToken = 'BE/s9XcA33ZXLiTl/ak3oXSu+pvkuewrU18T6xZChc9v/JYbMyYfAB3a0algBvj+q80PGUAjsl9UAwHD4BJxuYmsLaxaP3UlQyOjiDfSmDA7Jq8OphhSoDSmxycFIK7RV5tl1HTie6tGM9R6HLQgbxTTz03chsVY4LpWM7reM1FsSA1y/pbMsVVDTj7wx/ZBuYGh+0TLhdbEZD+N+g7TQVUkU2kxONCZ5T2Gi+0u7wwP7m/h/mgQHIzDYYQAe8F4rydJficMnedRH+jRr+eTEsr1V1a9K6/an2MyZGAkyVkXNO4mU0EVNTYaSoqLeXdUvYXsslQ/2/wOs+XlEp+X4GD2xLfKKELpc2KK8YuGvWLqRUr8aVS8moQ/ff4tk0MFR9ookE3sJF15roh8hgkXBw==';

  $ch = curl_init();
  $lang = "EN";

  if (get_locale() == "fr_CA")
    $lang = "FR";

  $url = "https://badgingapi.carfax.ca/api/v2/badges/" . $vin . "?accountNumber=" . $accountNumber . "&language=" . $lang . "";

  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  curl_setopt(
    $ch,
    CURLOPT_HTTPHEADER,
    array(
      'Accept: application/json',
      'WebServiceToken: ' . $WebServiceToken . ' '
    )
  );

  $resp = curl_exec($ch);

  if ($e = curl_error($ch)) {
    $e;
  } else {
    $decoded = json_decode($resp);

    if($decoded){
      if ($decoded->ResultCode == 1) {
        $badge = "<a href='" . $decoded->BadgesList[0]->VhrReportUrl . "' target='_blank'>
                                      <img class='pt-1 pb-1 m-auto' src='" . $decoded->BadgesList[0]->BadgesImageUrl . "'>
                              </a>";

        curl_close($ch);
        return $badge;
      }
    }
  }
}

function getGraphqlAuthToken()
{
  $endpoint = getGraphqlEndPoint();
  $request_body = wp_json_encode([
    'query' => '
          mutation LoginUser {
            login(
              input: {clientMutationId: "uniqueId", username: "content-reader", password: "6det@avt1$J3^NfdBL4FcgGL"}
            ) {
              authToken
            }
          }
        '
  ]);

  $response = wp_remote_request($endpoint, [
    'method' => 'POST',
    'timeout' => 50,
    'headers' => [
      'Content-Type' => 'application/json'
    ],
    'body' => $request_body
  ]);


  if (is_wp_error($response)) {
    throw new \Exception($response->get_error_message());
  }

  $decoded_response = json_decode($response['body'], true);
  $auth_token = $decoded_response['data']['login']['authToken'];

  return $auth_token;
}

function getGraphqlEndPoint() {
  $lbSettings = get_leadbox_settings();
  if (!isset($lbSettings['graphql_url']) || empty($lbSettings['graphql_url'])) {
    return 'https://minerva.stellate.sh/graphql';
  }else{
    return $lbSettings['graphql_url'];
  }
}

function get_adobe_vehicle_type($type)
{
  if (isset($type)) {
    if (isFrench()) {
      switch (strtolower($type)) {
        case 'voiture':
          return "car";
          break;
        case 'vus':
          return "suv";
          break;
        case 'camion':
          return "truck";
          break;
        case 'monospace':
          return "van";
          break;
        case 'utilitaire':
          return "commercial";
          break;
        default:
          return "car";
          break;
      }
    } else {
      if (strtolower(str_replace(' ', '', trim($type))) == "other") {
        return "car";
      } else {
        return strtolower(str_replace(' ', '', trim($type)));
      }

    }
  }

  //if there is not vehicle type set by default return car
  return "car";
}

function get_tax_from_province()
{
  $taxes = array(
    "AB" => 5,
    "BC" => 12,
    "MB" => 12,
    "NB" => 15,
    "NL" => 15,
    "NT" => 5,
    "NS" => 15,
    "NU" => 5,
    "ON" => 13,
    "PE" => 15,
    "QC" => 15,
    "SK" => 11,
    "YT" => 5
  );

  $contact = get_dealer_contact();

  if (isset($contact) && !empty($contact) && isset($contact["address_province"]) && !empty($contact["address_province"])) {
    if (isset($taxes[$contact["address_province"]]))
      return $taxes[$contact["address_province"]];
    else
      return 13;
  } else
    return 13;
}

function get_tax_label_province()
{
  $label = array(
    "AB" => 'GST',
    "BC" => 'GST + PST',
    "MB" => 'GST + PST',
    "NB" => 'HST',
    "NL" => 'HST',
    "NT" => 'GST',
    "NS" => 'HST',
    "NU" => 'GST',
    "ON" => 'HST',
    "PE" => 'HST',
    "QC" => 'GST + QST',
    "SK" => 'GST + PST',
    "YT" => 'GST'
  );

  $label_fr = array(
    "AB" => 'TPS',
    "BC" => 'TPS + TVP',
    "MB" => 'TPS + TVP',
    "NB" => 'TVH',
    "NL" => 'TVH',
    "NT" => 'TPS',
    "NS" => 'TVH',
    "NU" => 'TPS',
    "ON" => 'TVH',
    "PE" => 'TVH',
    "QC" => 'TPS + TVQ',
    "SK" => 'TPS + TVP',
    "YT" => 'TPS'
  );

  $contact = get_dealer_contact();

  if (isset($contact) && !empty($contact) && isset($contact["address_province"]) && !empty($contact["address_province"])) {
    $lang = get_locale();
    if ($lang == 'fr_CA'){
      if (isset($label_fr[$contact["address_province"]]))
        return $label_fr[$contact["address_province"]];
      else
        return 'TVH';
    }
    else{
      if (isset($label[$contact["address_province"]]))
        return $label[$contact["address_province"]];
      else
        return 'HST';
    }

  } else
    return 'HST';
}

function find_url($url = NULL)
{
  if (empty($url)) {
    return false;
  }
  $response = wp_remote_head($url, array('timeout' => 5));

  $accepted_response = array(200, 301, 302);
  if (!is_wp_error($response) && in_array(wp_remote_retrieve_response_code($response), $accepted_response)) {
    return true;
  } else {
    return false;
  }
}

/**
 * This function adds "async" and "defer" parameters to JavaScript resources.
 * Just add "async" or "defer" anywhere in the resource name
 * ("handle" attribute of the wp_register_script function).
 *
 * @param $tag
 * @param $handle
 *
 * @return mixed
 */
function add_async_defer_attributes_to_scripts($tag, $handle)
{
  // Search for the "async" value
  if (strpos($handle, "async")):
    $tag = str_replace(' src', ' async="async" src', $tag);
  endif;
  // Search for the "defer" value
  if (strpos($handle, "defer")):
    $tag = str_replace(' src', ' defer="defer" src', $tag);
  endif;
  return $tag;
}
add_filter('script_loader_tag', 'add_async_defer_attributes_to_scripts', 10, 2);


/**
 * Returns the finance amount based on dealer frequency.
 * @var int $price
 * @var float $rate
 * @var int $term
 *
 * @return int $financeTotal
 */

function getFinanceTotal($price = int, $rate = float, $term = int)
{
  if ($price != 0 && $rate != 0 && $term != 0) {
    $financeTotal = round(($price * ($rate / 1200) * pow(1 + ($rate / 1200), $term)) / (pow(1 + ($rate / 1200), $term) - 1) * 100) / 100;
    $financeTotal = round($financeTotal, 2);

    switch (get_leadbox_finance_settings()['finance_frequency']) {
      case 'Weekly':
        $financeTotal = round(($financeTotal * 12) / 52);
        break;
      case 'Bi-Weekly':
        $financeTotal = round(((($financeTotal * 12) / 52) * 2));
        break;
      case 'Monthly':
        $financeTotal = round($financeTotal);
        break;
    }
    return $financeTotal;
  }
  return null;
}

/**
 * Returns the lease amount based on dealer frequency.
 * @var int $price
 * @var int $term
 * @var float $rate
 * @var int $adjustment
 * @var int $residual
 *
 * @return int $leaseTotal
 */
function getLeaseTotal($price = int, $term = int, $rate = float, $residual = int)
{
  $moneyFactor = ($rate / 2400);
  $newResidual = $price * ($residual / 100);
  $depretiation = 0;
  if ($term > 0)
    $depretiation = ($price - ($price * ($residual / 100))) / $term;
  $financeFee = ($price + $newResidual) * $moneyFactor;
  $monthlyLease = $financeFee + $depretiation;

  switch (get_leadbox_finance_settings()['lease_frequency']) {
    case 'Weekly':
      $leaseTotal = round(($monthlyLease * 12) / 52);
      break;
    case 'Bi-Weekly':
      $leaseTotal = round((($monthlyLease * 12) / 26));
      break;
    case 'Monthly':
      $leaseTotal = round($monthlyLease);
      break;
  }
  return $leaseTotal;
}

/**
 * Returns the structure that a custom sitemap must have in order to be readable by Yoast.
 *
 * @param string $url
 *
 * @return string $output
 */

function create_custom_sitemap_url($url)
{
  $url = htmlspecialchars($url);

  $output = "\t<url>\n";
  $output .= "\t\t<loc>" . $url . "</loc>\n";
  $output .= '';
  $output .= "\t\t<lastmod>" . date('c', time()) . "</lastmod>\n";
  $output .= "\t</url>\n";

  return $output;
}

function cmp($a, $b)
{
  $keyA = ($a['model'] ?? '') . ($a['year'] ?? '');
  $keyB = ($b['model'] ?? '') . ($b['year'] ?? '');

  if ($keyA == $keyB) {
    return 0;
  }
  return ($keyA < $keyB) ? -1 : 1;
}

/**
 * Returns the first segment of URL.
 *
 *
 * @return string $output
*/

function check_url_first_segment() {
  $current_url = $_SERVER['REQUEST_URI'];
  $url_segments = explode('/', trim($current_url, '/'));
  if (isset($url_segments[0])) {
      return strtolower($url_segments[0]);
  } else {
      return "";
  }
}

function get_local_dealer_stores()
{
  $route = '/resources/config/dealer-stores.json';
  $jsonPath = get_fileInGenius($route);
  if (file_exists($jsonPath . $route)) {
    return json_decode(file_get_contents($jsonPath . $route), true);
  } else {
    return null;
  }
}

function get_dealer_stores($store) {
  $dealerStores = get_local_dealer_stores();
  if(isset($dealerStores) && !empty($dealerStores) && isset($dealerStores['stores']) && !empty($dealerStores['stores'])) {
    $dealerStores = $dealerStores['stores'];
    foreach ($dealerStores as $dealerStore) {
      if ($dealerStore['lblocation'] == $store) {
        return $dealerStore;
      }
    }
    return null;
  }
  else {
    return null;
  }

}

/**
 * Owning-site geo payload for the vehicle-card distance badge.
 *
 * Every vehicle on this site sits at the dealer (e.g. Derrick Dodge), so the
 * badge shows the dealer city plus how far the BUYER is from it. This exposes
 * the dealer's coordinates + city from Dealer Settings → Contact
 * (`dealer-settings-contact-options`); the buyer side (geolocation + haversine)
 * is computed client-side in spa-vehicle-card.vue.
 *
 * Returns null when the vehicle-card `show-location-distance` option is off, or
 * when there is neither coordinates nor a city to show — keeping the badge fully
 * opt-in. Consumed through the window.LBX_DEALER_LOCATION global injected in
 * head.blade.php.
 *
 * @return array{lat: ?float, lng: ?float, city: string, name: string, locations: ?array<string, array{city: string, lat: ?float, lng: ?float}>}|null
 */
function get_dealer_geo_payload() {
  $enabled = defined('GENIUS') && (
    (GENIUS['vehicle-card']['data']['show-location-distance'] ?? false)
    || (GENIUS['vdp-title']['data']['show-location-distance'] ?? false)
  );
  if (!$enabled) {
    return null;
  }

  $contact = get_dealer_contact();
  if (empty($contact)) {
    return null;
  }

  $latRaw = isset($contact['latitude']) ? lbx_normalize_coordinate($contact['latitude']) : '';
  $lngRaw = isset($contact['longitude']) ? lbx_normalize_coordinate($contact['longitude']) : '';
  $city   = isset($contact['address_city']) ? trim($contact['address_city']) : '';
  $name   = isset($contact['dealer_name']) ? trim($contact['dealer_name']) : '';

  // Per-store overrides for multi-location inventories: GENIUS['locations'] maps
  // a vehicle's `location` (store name from the feed) to its own city and,
  // optionally, coordinates. Entries can be "Store" => "City" or
  // "Store" => { city, lat, lng }. Vehicles whose location is not in the map
  // keep the owning-site city/coords above.
  $locations = [];
  $rawLocations = GENIUS['locations'] ?? [];
  if (is_array($rawLocations)) {
    foreach ($rawLocations as $store => $entry) {
      if (is_string($entry)) {
        $entry = ['city' => $entry];
      }
      if (!is_array($entry)) {
        continue;
      }
      $entryCity = isset($entry['city']) ? trim((string) $entry['city']) : '';
      $entryLat  = isset($entry['lat']) ? lbx_normalize_coordinate($entry['lat']) : '';
      $entryLng  = isset($entry['lng']) ? lbx_normalize_coordinate($entry['lng']) : '';
      if ($entryCity === '' && $entryLat === '' && $entryLng === '') {
        continue;
      }
      $locations[$store] = [
        'city' => $entryCity,
        'lat'  => $entryLat !== '' ? (float) $entryLat : null,
        'lng'  => $entryLng !== '' ? (float) $entryLng : null,
      ];
    }
  }

  // No coordinates, no city and no per-store map => nothing worth showing.
  if ($latRaw === '' && $lngRaw === '' && $city === '' && empty($locations)) {
    return null;
  }

  return [
    'lat'  => $latRaw !== '' ? (float) $latRaw : null,
    'lng'  => $lngRaw !== '' ? (float) $lngRaw : null,
    'city' => $city,
    'name' => $name,
    'locations' => !empty($locations) ? $locations : null,
    // Which surfaces show the badge — so each only prompts for geolocation when
    // its own badge is on (e.g. SRP off + VDP on => no prompt on the listing).
    'srp'  => (bool) (GENIUS['vehicle-card']['data']['show-location-distance'] ?? false),
    'vdp'  => (bool) (GENIUS['vdp-title']['data']['show-location-distance'] ?? false),
    // City-only mode: `show-location-distance` set to "city" shows the store
    // city but never prompts for geolocation nor renders a distance.
    'srpCityOnly' => strtolower((string) (GENIUS['vehicle-card']['data']['show-location-distance'] ?? '')) === 'city',
    'vdpCityOnly' => strtolower((string) (GENIUS['vdp-title']['data']['show-location-distance'] ?? '')) === 'city',
  ];
}


function is_store_open($hours) {
  try {
    $timezone = wp_timezone();
  } catch (Exception $e) {
    $timezone = new DateTimeZone('Canada/Eastern');
  }

  $now = new DateTime('now', $timezone);

  if (empty($hours) || !str_contains($hours, '-') || stripos($hours, 'closed') !== false) {
    return "Closed";
  }

  $split_hours = explode("-", $hours);

  $hours_start = DateTime::createFromFormat('g:i A', trim($split_hours[0]), $timezone);
  $hours_end = DateTime::createFromFormat('g:i A', trim($split_hours[1]), $timezone);

  if ($hours_start && $hours_end) {
    if ($hours_end < $hours_start) {
      $hours_end->modify('+1 day');
    }

    if ($now >= $hours_start && $now <= $hours_end) {
      return "Open";
    }
  }

  return "Closed";
}

function findStatusInInventory($status)
{
  $inventory = get_search_inventory();
  $count = 0;

  $vehicles = array_filter($inventory, function ($vehicle) use ($status, &$count) {
    if ($status == 'certified' && $vehicle['certified']) {
      $count++;
      return true;
    } else if ($status == 'salepending' && $vehicle['salepending']) {
      $count++;
      return true;
    } else if ($status == 'special' && $vehicle['special']) {
      $count++;
      return true;
    } else if ($status == 'new' && $vehicle['condition'] == 'New') {
      $count++;
      return true;
    } else if ($status == 'used' && $vehicle['condition'] == 'Used') {
      $count++;
      return true;
    }
    return false;
  });

  return $count;
}

function textSalePhone() {
  if (!isFrench()) {
    return 'Sales';
  } else {
    return 'Ventes';
  }
}
function textServicePhone() {
  if (!isFrench()) {
    return 'Service';
  } else {
    return 'Service';
  }
}
function textPartsPhone() {
  if (!isFrench()) {
    return 'Parts';
  } else {
    return 'Pièces';
  }
}

function is_current_time_in_range($timeRange, $currentTime) {
  $isFrench = function_exists('isFrench') && isFrench();

  // Considerar "Closed" o "Fermé" como cerrado
  if ($timeRange === 'Closed' || ($isFrench && $timeRange === 'Fermé')) {
      return false;
  }

  // Separar la hora de inicio y fin del rango, soportando diferentes tipos de guion
  $timeParts = preg_split('/\s*[-–—]\s*/', $timeRange);
  if (count($timeParts) < 2) return false; // Si no hay un rango válido, retorna falso

  [$start, $end] = $timeParts;

  // Convertir ambas a timestamps comparables
  $startTime = strtotime($start);
  $endTime = strtotime($end);
  $now = strtotime($currentTime);

  return ($now >= $startTime && $now <= $endTime);
}


// Función para agrupar días consecutivos con soporte para francés
function group_consecutive_days($days) {
  $grouped = [];
  $temp = [];

  // Determinar si es francés
  $isFrench = function_exists('isFrench') && isFrench();

  // Usar el orden correcto según el idioma
  $dayOrder = $isFrench
      ? ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"]
      : ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];

  foreach ($dayOrder as $day) {
      if (in_array($day, $days)) {
          $temp[] = $day;
      } else {
          if (!empty($temp)) {
              $grouped[] = $temp;
              $temp = [];
          }
      }
  }

  if (!empty($temp)) {
      $grouped[] = $temp;
  }

  return $grouped;
}

// Función para agrupar horarios con soporte para francés
function group_hours($hours) {
    $groupedHours = [];

    // Definir los días en inglés y su equivalente en francés
    $dayOrder = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
    $dayOrderFr = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"];

    // Determinar si se debe traducir
    $isFrench = function_exists('isFrench') && isFrench();
    $dayMap = array_combine($dayOrder, $isFrench ? $dayOrderFr : $dayOrder);

    foreach ($hours as $day => $time) {
        $translatedDay = $dayMap[$day] ?? $day; // Traducir días si es necesario
        $translatedTime = ($isFrench && $time === "Closed") ? "Fermé" : $time; // Traducir "Closed" a "Fermé"
        $groupedHours[$translatedTime][] = $translatedDay;
    }

    // Ordenar los días dentro de cada grupo
    foreach ($groupedHours as $time => &$days) {
        $daysOrder = $isFrench ? $dayOrderFr : $dayOrder;

        usort($days, function($a, $b) use ($daysOrder) {
            return array_search($a, $daysOrder) <=> array_search($b, $daysOrder);
        });
    }
    unset($days);

    return $groupedHours;
}


function get_meta_yoast_inventory() {
  // Ruta al archivo inventory.json
  $inventory_file = wp_get_upload_dir()['basedir'] . '/data/inventory.json';

  // Verificar si el archivo existe
  if (!file_exists($inventory_file)) {
      return []; // Retornar un array vacío si el archivo no existe
  }

  // Leer y decodificar el archivo JSON
  $inventory = json_decode(file_get_contents($inventory_file), true);
  if (json_last_error() !== JSON_ERROR_NONE || !isset($inventory['vehicles'])) {
      return [];
  }

  $urls = []; // Array para almacenar las URLs
  $current_language = get_locale();

  //* Recorrer los vehículos en el inventario
  foreach ($inventory['vehicles'] as $item) {
      // Obtener la URL en el idioma actual

      $slug = get_vdp_slug($item, $current_language);
      $useVin = GENIUS['vehicle-card']['data']['use-slug-vin'] ?? false;
      if ($useVin) {
        $slug = str_replace('-' . $item['id'], '-' . $item['vin'] . '-' . $item['id'], $slug);
      }
      $full_url = get_site_url() . $slug;
      array_push($urls, $full_url);

      //* Si Polylang está activo y el idioma actual no es francés, agregar la URL en francés
      if (function_exists('pll_default_language') && $current_language !== 'fr_FR') {
          $slug_fr = get_vdp_slug($item, 'fr');
          $full_url_fr = get_site_url() . $slug_fr;
          array_push($urls, $full_url_fr);
      }
  }

  return $urls; // Retornar el array de URLs
}

function generate_sitemap_xml() {
  // Obtener las URLs del inventario
  $urls = get_meta_yoast_inventory();

  // Crear el elemento raíz del XML
  $xml = new SimpleXMLElement('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"/>');

  // Iterar sobre las URLs y añadirlas al XML
  foreach ($urls as $url) {
      $url_node = $xml->addChild('url');
      $url_node->addChild('loc', $url);
      $url_node->addChild('lastmod', date('Y-m-d')); // Fecha actual
      $url_node->addChild('changefreq', 'weekly');   // Frecuencia de cambio
      $url_node->addChild('priority', '0.7');       // Prioridad
  }

  // Devolver el XML como una cadena
  header('Content-Type: text/xml');
  echo $xml->asXML();
  exit;
}


function my_sitemap_rewrite_custom() {
  add_rewrite_rule('^inventory\.xml$', 'index.php?custom_xml_sitemap=true', 'top');
}
function custom_xml_sitemap_query_var($vars) {
  $vars[] = 'custom_xml_sitemap';
  return $vars;
}

function custom_xml_sitemap_request($wp) {
  if (isset($wp->query_vars['custom_xml_sitemap']) && $wp->query_vars['custom_xml_sitemap'] === 'true') {
      generate_sitemap_xml();
  }
}

function removeAccents($string)
{
  $table = array(
    'Š' => 'S',
    'š' => 's',
    'Đ' => 'Dj',
    'đ' => 'dj',
    'Ž' => 'Z',
    'ž' => 'z',
    'Č' => 'C',
    'č' => 'c',
    'Ć' => 'C',
    'ć' => 'c',
    'À' => 'A',
    'Á' => 'A',
    'Â' => 'A',
    'Ã' => 'A',
    'Ä' => 'A',
    'Å' => 'A',
    'Æ' => 'A',
    'Ç' => 'C',
    'È' => 'E',
    'É' => 'E',
    'Ê' => 'E',
    'Ë' => 'E',
    'Ì' => 'I',
    'Í' => 'I',
    'Î' => 'I',
    'Ï' => 'I',
    'Ñ' => 'N',
    'Ò' => 'O',
    'Ó' => 'O',
    'Ô' => 'O',
    'Õ' => 'O',
    'Ö' => 'O',
    'Ø' => 'O',
    'Ù' => 'U',
    'Ú' => 'U',
    'Û' => 'U',
    'Ü' => 'U',
    'Ý' => 'Y',
    'Þ' => 'B',
    'ß' => 'Ss',
    'à' => 'a',
    'á' => 'a',
    'â' => 'a',
    'ã' => 'a',
    'ä' => 'a',
    'å' => 'a',
    'æ' => 'a',
    'ç' => 'c',
    'è' => 'e',
    'é' => 'e',
    'ê' => 'e',
    'ë' => 'e',
    'ì' => 'i',
    'í' => 'i',
    'î' => 'i',
    'ï' => 'i',
    'ð' => 'o',
    'ñ' => 'n',
    'ò' => 'o',
    'ó' => 'o',
    'ô' => 'o',
    'õ' => 'o',
    'ö' => 'o',
    'ø' => 'o',
    'ù' => 'u',
    'ú' => 'u',
    'û' => 'u',
    'ý' => 'y',
    'ý' => 'y',
    'þ' => 'b',
    'ÿ' => 'y',
    'Ŕ' => 'R',
    'ŕ' => 'r',
  );

  return strtr($string, $table);
}

function get_lineup_totals_for_navigation($lineup, $condition)
{
    $inventory = get_search_inventory();
    $conditionLower = strtolower($condition);

    // Reglas especiales: nombre del lineup => función de matching
    $specialRules = [
        'f-150' => fn($v, $field) => preg_match("/f-150(?! lightning)/i", $v[$field] ?? ''),
        'bronco' => fn($v, $field) => ($v[$field] ?? '') === 'bronco',
        'f-150 lightning' => fn($v, $field) => ($v[$field] ?? '') === 'f-150 lightning',
        'transit' => fn($v, $field) => ($v[$field] ?? '') === 'transit',
        'transit electric' => fn($v, $field) => ($v[$field] ?? '') === 'e-transit',
        'shelby f-150' => fn($v, $field) => ($v['model'] ?? '') === 'f-150' && stripos($v['tags'] ?? '', 'shelby') !== false,
        'roush mustang' => fn($v, $field) => ($v['model'] ?? '') === 'mustang' && stripos($v['tags'] ?? '', 'roush') !== false,
        'roush f-150' => fn($v, $field) => ($v['model'] ?? '') === 'f-150' && stripos($v['tags'] ?? '', 'roush') !== false,
        'roush f-250' => fn($v, $field) => stripos($v['model'] ?? '', 'f-250') !== false && stripos($v['tags'] ?? '', 'roush') !== false,
        'bronco raptor' => fn($v, $field) => stripos($v['model'] ?? '', 'bronco') !== false && stripos($v['trim'] ?? '', 'raptor') !== false,
        'ranger raptor' => fn($v, $field) => stripos($v['model'] ?? '', 'ranger') !== false && stripos($v['trim'] ?? '', 'raptor') !== false,
        'f-150 raptor' => fn($v, $field) => stripos($v['model'] ?? '', 'f-150') !== false && stripos($v['trim'] ?? '', 'raptor') !== false,
    ];

    // Casos especiales que ignoran la condición
    $specialNoCondition = ['roush mustang', 'shelby f-150', 'roush f-150', 'roush f-250', 'bronco raptor', 'ranger raptor', 'f-150 raptor'];

    // Pre-normalizar vehículos una sola vez
    $normalizedInventory = [];
    foreach ($inventory as $vehicle) {
        if (!isset($vehicle['condition'])) continue;

        $normalizedInventory[] = [
            'original' => $vehicle,
            'condition' => strtolower($vehicle['condition']),
            'model' => strtolower($vehicle['model'] ?? ''),
            'trim' => strtolower($vehicle['trim'] ?? ''),
            'tags' => strtolower($vehicle['tags'] ?? ''),
        ];
    }

    foreach ($lineup as &$item) {
        $total = 0;
        $nameLower = strtolower($item['name'] ?? '');
        $field = $item['field'] ?? '';
        $regex = $item['regex'] ?? '';
        $specialRule = $specialRules[$nameLower] ?? null;
        $isSpecialNoCondition = in_array($nameLower, $specialNoCondition);

        foreach ($normalizedInventory as $nv) {
            $vehicle = $nv['original'];
            $matchesCondition = $nv['condition'] === $conditionLower;

            if (!$matchesCondition && !$isSpecialNoCondition) continue;

            if ($specialRule) {
                $vehicleLower = [
                    'model' => $nv['model'],
                    'trim' => $nv['trim'],
                    'tags' => $nv['tags'],
                    $field => strtolower($vehicle[$field] ?? ''),
                ];
                if ($specialRule($vehicleLower, $field)) {
                    $total++;
                }
            } elseif ($matchesCondition && $regex) {
                $fieldValue = strtolower($vehicle[$field] ?? '');
                if (preg_match($regex, $fieldValue)) {
                    $total++;
                }
            }
        }

        $item['total'] = $total;
    }

    return $lineup;
}

function prepare_grouped_hours($groupedHours)
{
    $isFrench = function_exists('isFrench') && isFrench();

    $dayOrder = $isFrench ? ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'] : ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];

    $entries = [];

    foreach ($groupedHours as $time => $days) {
        foreach (group_consecutive_days($days) as $group) {
            $entries[] = [
                'days' => $group,
                'time' => $time,
                'firstIndex' => array_search($group[0], $dayOrder),
            ];
        }
    }

    usort($entries, fn($a, $b) => $a['firstIndex'] <=> $b['firstIndex']);

    return $entries;
}

/**
 * Obtener ID de formulario Ninja Forms por nombre (cacheado en opciones)
 */
function lbx_remember_transient( $key, $callback, $expiration = HOUR_IN_SECONDS ) {
    $cached = get_transient( $key );
    if ( $cached !== false ) {
        return $cached;
    }
    $value = is_callable($callback) ? $callback() : null;
    set_transient( $key, $value, $expiration );
    return $value;
}

// Obtener todos los formularios [id => título]
function _lbx_get_all_forms() {
    if ( ! function_exists('Ninja_Forms') ) return [];
    $forms = Ninja_Forms()->form()->get_forms();
    return collect($forms)
        ->mapWithKeys(fn($form) => [(int) $form->get_id() => (string) $form->get_setting('title')])
        ->toArray();
}

function lbx_get_all_forms() {
    return lbx_remember_transient('lbx_all_ninja_forms', '_lbx_get_all_forms', DAY_IN_SECONDS);
}

// Normalizar nombres
function lbx_normalize_form_name( $name ) {
    $name = strtolower( remove_accents( (string) $name ) );
    $name = str_replace('-', ' ', $name);
    $name = preg_replace('/[^\p{L}\p{N}\s]+/u', ' ', $name);
    $name = preg_replace('/\s+/u', ' ', $name);
    return trim($name);
}

// Mapa normalizado => ID (cacheado)
function lbx_get_forms_name_map() {
    return lbx_remember_transient('lbx_nf_name_map', function () {
        $forms = lbx_get_all_forms(); // [id => title]
        $map = [];
        foreach ($forms as $id => $title) {
            $norm = lbx_normalize_form_name($title);
            // Si hay duplicados, conserva el primero o define tu política
            if (!isset($map[$norm])) $map[$norm] = (int) $id;
        }
        return $map;
    }, DAY_IN_SECONDS);
}

// Lookup por nombre
function lbx_get_form_id_by_name( $form_name ) {
    if ( empty($form_name) ) return false;
    $norm = lbx_normalize_form_name($form_name);
    $map  = lbx_get_forms_name_map();
    return $map[$norm] ?? false;
}

function toLeadboxImageUrl($src, $size = '400') {
    if (!$src) {
        return null;
    }

    if (strpos($src, 'vehicleimages.leadboxhq.com') !== false) {
        return preg_replace('/^http:/i', 'https:', $src);
    }

    $pattern = '/https?:\/\/[^\/]*blob\.core\.windows\.net\/([^\/]+)\/vehicles\/([^\/]+)\/pictures\/([a-f0-9-]+)(?:-[A-Z]+)?(?:\.\w+)?$/i';
    if (preg_match($pattern, $src, $matches)) {
        $dealer = $matches[1];
        $vehicleId = $matches[2];
        $imageId = $matches[3];

        return "https://vehicleimages.leadboxhq.com/v1/{$dealer}/{$vehicleId}/{$imageId}-{$size}.jpg";
    }

    return $src;
}

// Invalidación cuando se guarda/actualiza un form
add_action('ninja_forms_save_form', function( $form_id ) {
    // Recalcula la lista y el mapa en caliente
    $all  = _lbx_get_all_forms();
    set_transient('lbx_all_ninja_forms', $all, DAY_IN_SECONDS);

    $map = [];
    foreach ($all as $id => $title) {
        $norm = lbx_normalize_form_name($title);
        if (!isset($map[$norm])) $map[$norm] = (int) $id;
    }
    set_transient('lbx_nf_name_map', $map, DAY_IN_SECONDS);
}, 9999, 1);

/**
 * ============================================================================
 * LEADBOX DATALAYER — Helpers (LBT-1395)
 * ============================================================================
 * Server-side support for window.dataLayer push of standardized lbx_* events.
 * The JS side reads window.LBX_CONTEXT injected in head.blade.php.
 */

/**
 * Master switch. All lbx_* tracking is skipped when this returns false.
 */
function is_lbx_datalayer_enabled()
{
    $s = get_option('leadbox-settings');
    return !empty($s['enable_lbx_datalayer'])
        && strtolower($s['enable_lbx_datalayer']) === 'enabled';
}

/**
 * Canonical Leadbox account identifier for this dealer.
 *
 * Single source of truth: if Ops defines a different canonical field later
 * (e.g. a constant, an API call, jlr_dealer_code), change ONLY this function.
 */
function get_lbx_account_id()
{
    $s = get_option('leadbox-settings');
    return !empty($s['leadbox_id']) ? $s['leadbox_id'] : null;
}

/**
 * Language code for the current request. Returns 'en' or 'fr'.
 */
function get_lbx_language()
{
    $locale = strtolower((string) get_locale());
    return strpos($locale, 'fr') === 0 ? 'fr' : 'en';
}

/**
 * Current page type per LBT-1395 spec (server-side detection).
 * Returns one of: homepage, vdp, srp, specials, contact, directions,
 * service, service_appointment, service_specials, parts, finance,
 * credit_application, trade, careers, about, blog, thank_you, other.
 *
 * Detection priority:
 *   1. vdp_string query var          (canonical VDP signal)
 *   2. Front page / blog home        (homepage)
 *   3. Known page slugs              (matches this theme's inventory, contact, etc.)
 *   4. Template filename pattern     (strpos over get_page_template_slug)
 *   5. Post type / archive fallbacks
 *   6. other
 */
function get_lbx_page_type()
{
    if (!empty(get_query_var('vdp_string'))) {
        return 'vdp';
    }
    if (is_front_page() || is_home()) {
        return 'homepage';
    }

    // --- Priority 3: match by WP page slug (most reliable in this theme) ---
    $slugMap = [
        'srp' => [
            'new-inventory', 'used-inventory',
            'inventaire-neufs', 'inventaire-doccasion',
        ],
        'contact'             => ['contact-us', 'contact', 'nous-joindre'],
        'directions'          => ['directions', 'hours-and-directions', 'heures-et-directions'],
        'specials'            => ['specials', 'special-offers', 'offers', 'promotions'],
        'service'             => ['service', 'service-department'],
        'service_appointment' => ['service-appointment', 'schedule-service', 'schedule-an-appointment', 'book-service', 'prendre-rendez-vous'],
        'service_specials'    => ['service-specials', 'service-coupons'],
        'parts'               => ['parts', 'pieces'],
        'finance'             => ['finance', 'financement'],
        'credit_application'  => ['credit-application', 'apply-for-credit', 'demande-de-credit'],
        'trade'               => ['trade-in', 'trade', 'evaluation', 'value-my-trade'],
        'build_and_price'     => ['build-and-price', 'build-price', 'configurer', 'configurez'],
        'careers'             => ['careers', 'carrieres', 'jobs'],
        'about'               => ['about-us', 'about', 'a-propos'],
        'thank_you'           => ['thank-you', 'thankyou', 'merci'],
    ];
    foreach ($slugMap as $type => $slugs) {
        if (is_page($slugs)) {
            return $type;
        }
    }

    // --- Priority 4: template filename pattern match ---
    $template = strtolower((string) get_page_template_slug());
    if ($template !== '') {
        if (strpos($template, 'srp') !== false) return 'srp';
        if (strpos($template, 'vdp') !== false
            || strpos($template, 'template-model') !== false
            || strpos($template, 'template-full-model') !== false
            || strpos($template, 'template-product') !== false) return 'vdp';
        if (strpos($template, 'homepage') !== false)          return 'homepage';
        if (strpos($template, 'service-appointment') !== false) return 'service_appointment';
        if (strpos($template, 'service-specials') !== false)   return 'service_specials';
        if (strpos($template, 'service') !== false)            return 'service';
        if (strpos($template, 'credit') !== false)             return 'credit_application';
        if (strpos($template, 'finance') !== false)            return 'finance';
        // Tester finding 5 (LBT-1395): build-and-price is a configurator, not
        // a trade-in tool. Ops approved a new 'build_and_price' page_type as a
        // Leadbox extension to the universal spec. Coordinate deploy with the
        // GTM container update so reporting doesn't blink.
        if (strpos($template, 'build-and-price') !== false) return 'build_and_price';
        if (strpos($template, 'trade') !== false) return 'trade';
        if (strpos($template, 'special-offers') !== false
            || strpos($template, 'offers') !== false
            || strpos($template, 'promotion') !== false)       return 'specials';
        if (strpos($template, 'contact') !== false)            return 'contact';
        if (strpos($template, 'directions') !== false)         return 'directions';
        if (strpos($template, 'parts') !== false)              return 'parts';
        if (strpos($template, 'careers') !== false)            return 'careers';
        if (strpos($template, 'about') !== false)              return 'about';
        if (strpos($template, 'thankyou') !== false
            || strpos($template, 'thank-you') !== false)       return 'thank_you';
        if (strpos($template, 'blog') !== false)               return 'blog';
    }

    // --- Priority 5: post type / archive fallbacks ---
    if (is_singular('post') || is_category() || is_tag() || is_archive()) {
        return 'blog';
    }

    return 'other';
}

/**
 * Best-effort department of the page the user came from, derived from the
 * HTTP referrer. Used so a thank_you page can "inherit from previous page"
 * per the spec. Only same-host referrers are trusted; returns null when the
 * referrer is missing, off-site, or doesn't map to a known department.
 */
function lbx_department_from_referer()
{
    $ref = isset($_SERVER['HTTP_REFERER']) ? (string) $_SERVER['HTTP_REFERER'] : '';
    if ($ref === '') {
        return null;
    }

    // Only trust same-host referrers so an external link can't spoof it.
    $refHost = strtolower((string) parse_url($ref, PHP_URL_HOST));
    $ownHost = strtolower((string) parse_url(home_url(), PHP_URL_HOST));
    if ($refHost !== '' && $ownHost !== '' && $refHost !== $ownHost) {
        return null;
    }

    $path = strtolower((string) parse_url($ref, PHP_URL_PATH));
    if ($path === '') {
        return null;
    }

    $rules = [
        'service' => ['/service', '/book-service', '/service-appointment', '/prendre-rendez-vous', '/rendez-vous'],
        'parts'   => ['/parts', '/pieces'],
        'finance' => ['/finance', '/financement', '/credit', '/demande-de-credit'],
        'sales'   => ['/new-inventory', '/used-inventory', '/inventaire', '/inventory', '/vehicle', '/vdp', '/trade', '/value-my-trade', '/build-and-price', '/specials', '/promotions'],
    ];
    foreach ($rules as $dept => $needles) {
        foreach ($needles as $needle) {
            if (strpos($path, $needle) !== false) {
                return $dept;
            }
        }
    }

    return null;
}

/**
 * Department inferred from page type. Used as default for lbx_page_view.
 */
function get_lbx_department_for_page_type($pageType)
{
    $map = [
        'homepage'            => 'general',
        'vdp'                 => 'sales',
        'srp'                 => 'sales',
        'specials'            => 'sales',
        'trade'               => 'sales',
        'contact'             => 'general',
        'directions'          => 'general',
        'service'             => 'service',
        'service_appointment' => 'service',
        'service_specials'    => 'service',
        'parts'               => 'parts',
        'finance'             => 'finance',
        'credit_application'  => 'finance',
        'careers'             => 'general',
        'about'               => 'general',
        'blog'                => 'general',
        'thank_you'           => 'general',
        'other'               => 'general',
    ];
    $dept = isset($map[$pageType]) ? $map[$pageType] : 'general';

    // thank_you "inherits from previous page" per the spec: derive the
    // department from the referring page when we can, else keep 'general'.
    if ($pageType === 'thank_you') {
        $inherited = lbx_department_from_referer();
        if ($inherited) {
            return $inherited;
        }
    }

    return $dept;
}

/**
 * Normalize a vehicle data array (from get_vehicle_by_id) into the shape
 * the dataLayer spec expects. Values are lowercased where string,
 * numeric where numeric, and null when unavailable.
 *
 * Field sources (from the per-vehicle {id}.json in uploads/data/):
 *   - condition     : 'condition' + 'certified' (used+certified → 'certified')
 *   - bodystyle     : 'bodystyle'
 *   - fuel_type     : 'fueltype'
 *   - mileage       : 'mileage'
 *   - msrp          : 'msrp' (left as-is even when 0, per user preference)
 *   - price         : 'price' (fallback 'saleprice')
 *   - discount_price: 'specialprice' if > 0, else null
 *   - incentive     : 'promocode' (no structured incentive name in feed)
 *   - location      : 'location'
 *   - status        : derived from incoming/salepending/reserved/ininventory
 *   - photo_count   : 'numberofpics' (authoritative; falls back to count(pictures))
 *   - days_in_inv   : 'age'
 *   - payment_*     : not in the JSON feed — populated client-side by calculator
 *
 * Returns null if the input is empty (non-VDP page).
 */
function get_lbx_vehicle_context($data)
{
    if (empty($data) || !is_array($data)) {
        return null;
    }

    $lc = function ($v) {
        if ($v === null || $v === '') return null;
        return strtolower(trim((string) $v));
    };
    $num = function ($v) {
        if ($v === null || $v === '' || !is_numeric($v)) return null;
        return $v + 0;
    };
    $positiveNum = function ($v) {
        if ($v === null || $v === '' || !is_numeric($v)) return null;
        $n = $v + 0;
        return $n > 0 ? $n : null;
    };

    // Condition: used+certified collapses to 'certified' per spec.
    $condition = $lc($data['condition'] ?? null);
    if ($condition === 'used' && !empty($data['certified'])) {
        $condition = 'certified';
    }

    // Inventory status: derive from the flags present in the feed.
    $status = null;
    if (!empty($data['salepending']) || !empty($data['reserved'])) {
        $status = 'sold';
    } elseif (!empty($data['incoming'])) {
        $status = 'in-transit';
    } elseif (array_key_exists('ininventory', $data) && $data['ininventory'] === false) {
        $status = 'on-order';
    } elseif (array_key_exists('ininventory', $data) && $data['ininventory'] === true) {
        $status = 'in-stock';
    } else {
        // ininventory is null/missing: if we have a stocknumber and onweb is true,
        // treat it as in-stock. Otherwise null.
        if (!empty($data['stocknumber']) && !empty($data['onweb'])) {
            $status = 'in-stock';
        }
    }

    // Photo count: 'numberofpics' is the authoritative feed value; fall back
    // to counting 'pictures' if that isn't present.
    $photoCount = null;
    if (isset($data['numberofpics']) && is_numeric($data['numberofpics'])) {
        $photoCount = (int) $data['numberofpics'];
    } elseif (isset($data['pictures']) && is_array($data['pictures'])) {
        $photoCount = count($data['pictures']);
    }

    // Discount price: the feed exposes 'specialprice' (0 means no special).
    $discountPrice = $positiveNum($data['specialprice'] ?? null);

    return [
        'vehicle_vin'               => $lc($data['vin'] ?? null),
        'vehicle_stock_number'      => $lc($data['stocknumber'] ?? null),
        'vehicle_condition'         => $condition,
        'vehicle_make'              => $lc($data['make'] ?? null),
        'vehicle_model'             => $lc($data['model'] ?? null),
        'vehicle_year'              => $num($data['year'] ?? null),
        'vehicle_trim'              => $lc($data['trim'] ?? null),
        'vehicle_bodystyle'         => $lc($data['bodystyle'] ?? null),
        'vehicle_fuel_type'         => $lc($data['fueltype'] ?? ($data['fuel'] ?? null)),
        'vehicle_mileage'           => $num($data['mileage'] ?? null),
        'vehicle_msrp'              => $num($data['msrp'] ?? null),
        'vehicle_price'             => $num($data['price'] ?? ($data['saleprice'] ?? null)),
        'vehicle_discount_price'    => $discountPrice,
        'vehicle_incentive_name'    => $lc($data['promocode'] ?? null),
        'vehicle_payment_monthly'   => null,
        'vehicle_payment_type'      => null,
        'vehicle_location'          => $lc($data['location'] ?? null),
        'vehicle_status'            => $status,
        'vehicle_photo_count'       => $photoCount,
        'vehicle_days_in_inventory' => $num($data['age'] ?? null),
    ];
}

/**
 * Build the full LBX_CONTEXT payload injected into window in head.blade.php.
 * Returns null when tracking is disabled so callers can skip the <script> block.
 */
function get_lbx_context_payload($vehicleData = null)
{
    if (!is_lbx_datalayer_enabled()) {
        return null;
    }

    $pageType = get_lbx_page_type();
    $location = get_lbx_dealer_location();

    return [
        'leadbox_id'       => get_lbx_account_id(),
        'page_type'        => $pageType,
        'department'       => get_lbx_department_for_page_type($pageType),
        'language'         => get_lbx_language(),
        'vehicle'          => get_lbx_vehicle_context($vehicleData),
        // Tester finding 9 (LBT-1395 round 2): make dealer name and full
        // address available as page-global fallback for lbx_directions_click,
        // so anchors that don't carry per-click data-lbx-location-* still
        // emit usable values instead of null / leaked template tokens.
        'location_name'    => $location['name'],
        'location_address' => $location['address'],
    ];
}

/**
 * Single dealer location for the dataLayer. Returns null fields when the
 * dealer settings are empty, which signals to the JS to keep the field null
 * rather than fall back to anchor textContent (where it would pick up
 * unfilled template placeholders like "*address_line_1*").
 */
function get_lbx_dealer_location()
{
    $c = get_dealer_contact();
    if (!is_array($c)) {
        return ['name' => null, 'address' => null];
    }
    $name = !empty($c['dealer_name']) ? trim($c['dealer_name']) : null;
    $parts = [];
    foreach (['address_line_1', 'address_line_2', 'address_city', 'address_province', 'address_postal_code'] as $k) {
        if (!empty($c[$k]) && strpos($c[$k], '*') !== 0) {
            $parts[] = trim($c[$k]);
        }
    }
    return [
        'name'    => $name,
        'address' => $parts ? implode(', ', $parts) : null,
    ];
}