(function peaklineServiceCards() {
  'use strict';

  /* =========================================================
     PEAKLINE — CARDS OTA V2.5
     SOLO TARJETAS DEL HOME / LISTADO

     CAMBIOS RESPECTO A V2.4 (fix multimoneda):

     - El precio se formatea SIEMPRE con formatToLocaleMoney(),
       que aplica la conversión a la moneda que está viendo
       el comprador y pone el código correcto delante.

     - Ya no se mezclan fuentes: o usamos los datos crudos de
       `services` (y convertimos), o reutilizamos tal cual el
       texto que Vivirly ya renderizó (que ya viene convertido).
       Nunca se re-formatea un número ya convertido.

     - El id del servicio también se saca del enlace de la
       tarjeta, para que funcione en servicios con varias
       opciones de precio o con fechas abiertas (esos no
       renderizan el input de cantidad).

     IMPORTANTE:
     NO modifica las tarjetas internas del flujo de reserva.
     ========================================================= */


  /* =========================================================
     01 — UTILIDADES
     ========================================================= */

  function cleanText(value) {
    return String(value || '')
      .replace(/\s+/g, ' ')
      .trim();
  }


  function toAmount(value) {

    if (typeof value === 'number') {
      return isFinite(value) ? value : 0;
    }

    if (
      value === null ||
      typeof value === 'undefined'
    ) {
      return 0;
    }

    var text = String(value)
      .replace(/\s/g, '')
      .replace(/[^\d.,-]/g, '');

    text = text.replace(/,/g, '');

    var number = parseFloat(text);

    return isNaN(number) ? 0 : number;
  }


  /* =========================================================
     02 — IDENTIFICAR TARJETA VÁLIDA DEL HOME
     ========================================================= */

  function isHomeCard(card) {

    if (!card) {
      return false;
    }

    /*
      MUY IMPORTANTE:
      Las tarjetas del proceso de reserva usan
      .service-selection.

      Esas NO deben modificarse.
    */

    if (
      card.classList.contains('service-selection') ||
      card.closest('.service-selection')
    ) {
      return false;
    }


    /*
      Solo procesamos tarjetas dentro de listados
      o carruseles públicos.
    */

    if (
      card.closest('.service-list') ||
      card.closest('.vly-services-carousel-track')
    ) {
      return true;
    }

    return false;
  }


  /* =========================================================
     03 — DATOS DEL SERVICIO
     ========================================================= */

  function getServiceIdFromCard(card) {

    /*
      Camino 1: input de cantidad.
      No existe en servicios con varias opciones de precio
      ni en los de fechas abiertas.
    */

    var input = card.querySelector(
      'input[id^="input-service-"]'
    );

    if (input) {

      var fromInput = parseInt(
        input.id.replace('input-service-', ''),
        10
      );

      if (!isNaN(fromInput)) {
        return fromInput;
      }
    }


    /*
      Camino 2: enlace al detalle.
      Ruta: /{slug}/{id}/service_detail
    */

    var link = card.querySelector(
      'a.link-to-details[href]'
    );

    if (link) {

      var match = link
        .getAttribute('href')
        .match(/\/(\d+)\/service_detail/);

      if (match) {
        return parseInt(match[1], 10);
      }
    }

    return null;
  }


  function getServiceData(card) {

    var serviceId = getServiceIdFromCard(card);

    if (
      serviceId === null ||
      typeof services === 'undefined' ||
      !Array.isArray(services)
    ) {
      return null;
    }

    return services.find(function (service) {
      return Number(service.id) === Number(serviceId);
    }) || null;
  }


  /* =========================================================
     04 — PRECIO NATIVO
     ========================================================= */

  function getNativePriceText(card) {

    var price = card.querySelector(
      '.service-item__price'
    );

    return price
      ? cleanText(price.textContent)
      : '';
  }


  /*
    Devuelve el primer importe ya formateado por Vivirly,
    tal cual, sin volver a parsearlo ni re-formatearlo.

    "Precio: USD $70.92"                      -> "USD $70.92"
    "USD $65 (Reservas con USD $30 ahora...)" -> "USD $65"
  */

  function getNativeFormattedPrice(text) {

    if (!text) {
      return '';
    }

    var match = cleanText(text).match(
      /([A-Z]{3}\s*)?[$€£]\s*[\d][\d.,]*|[\d][\d.,]*\s*[$€£]/
    );

    if (match) {
      return cleanText(match[0]);
    }


    /* Fallback: quitamos la etiqueta y el paréntesis */

    var fallback = cleanText(text).split('(')[0];

    var colon = fallback.indexOf(':');

    if (colon !== -1) {
      fallback = fallback.slice(colon + 1);
    }

    return cleanText(fallback);
  }


  /* =========================================================
     05 — MONEDA
     ========================================================= */

  /*
    Moneda EN LA QUE ESTÁ CARGADO el precio del servicio.
    NO es la moneda que ve el comprador: de la conversión
    a la moneda de visualización se encarga
    formatToLocaleMoney().

    Si no la podemos determinar devolvemos null para que el
    helper use la moneda base del negocio.
  */

  function getCurrencyCode(service) {

    if (!service) {
      return null;
    }

    var candidates = [
      service.currencyCode,

      typeof service.currency === 'string'
        ? service.currency
        : null,

      service.currency &&
      service.currency.code
        ? service.currency.code
        : null
    ];

    for (
      var i = 0;
      i < candidates.length;
      i++
    ) {

      var value = cleanText(
        candidates[i]
      ).toUpperCase();

      if (/^[A-Z]{3}$/.test(value)) {
        return value;
      }
    }

    return null;
  }


  /*
    Formatea un importe crudo de `services`.
    formatToLocaleMoney() convierte a la moneda activa
    del comprador y antepone el código correcto.
  */

  function formatPrice(amount, service) {

    var number = toAmount(amount);

    var currency = getCurrencyCode(service);

    if (typeof formatToLocaleMoney === 'function') {
      return formatToLocaleMoney(number, currency);
    }


    /* Fallback defensivo: sin conversión, pero sin mentir
       con el código de moneda */

    var formatted = number.toLocaleString(
      'es-MX',
      {
        minimumFractionDigits: 0,
        maximumFractionDigits: 2
      }
    );

    return currency
      ? currency + ' $' + formatted
      : '$' + formatted;
  }


  /* =========================================================
     06 — PRECIO FINAL
     ========================================================= */

  function buildPriceText(card, service) {

    /*
      PRIORIDAD 1
      Datos crudos de `services` + conversión con el helper.
    */

    if (service) {

      var basePrice =
        toAmount(service.price);

      var remaining =
        toAmount(
          service.remainingAmount
        );

      var total = remaining > 0
        ? basePrice + remaining
        : basePrice;

      if (total > 0) {
        return formatPrice(total, service);
      }
    }


    /*
      PRIORIDAD 2
      Sin datos del servicio: reutilizamos el texto que
      Vivirly ya renderizó, que YA viene convertido y
      etiquetado. No lo volvemos a formatear.
    */

    return getNativeFormattedPrice(
      getNativePriceText(card)
    );
  }


  /* =========================================================
     07 — DURACIÓN
     ========================================================= */

  function getDuration(card) {

    var element = card.querySelector(
      '.service-item__extra-duration .service__duration-category'
    );

    if (!element) {
      element = card.querySelector(
        '.service__duration-category'
      );
    }

    return element
      ? cleanText(element.textContent)
      : '';
  }


  /* =========================================================
     08 — TÍTULO
     ========================================================= */

  function getTitleData(card) {

    var element = card.querySelector(
      '.service-item__title'
    );

    if (!element) {
      return {
        title: '',
        subtitle: ''
      };
    }

    var fullTitle = cleanText(
      element.textContent
    );

    var title = fullTitle;
    var subtitle = '';

    var match = fullTitle.match(
      /\s[\u2013\u2014-]\s/
    );

    if (match) {

      var index = match.index;

      title = fullTitle
        .substring(0, index)
        .trim();

      subtitle = fullTitle
        .substring(
          index +
          match[0].length
        )
        .trim();
    }

    return {
      title: title,
      subtitle: subtitle
    };
  }


  /* =========================================================
     09 — LIMPIAR VERSIÓN ANTERIOR
     ========================================================= */

  function removeOldElements(card) {

    var selectors = [
      '.ota-card-overlay',
      '.ota-duration-badge',
      '.ota-group-badge',
      '.ota-card-body',
      '.ota-discount-badge'
    ];

    selectors.forEach(function (selector) {

      card
        .querySelectorAll(selector)
        .forEach(function (element) {
          element.remove();
        });

    });
  }


  /* =========================================================
     10 — CONSTRUIR TARJETA
     ========================================================= */

  function buildCard(card, attempt) {

    attempt = attempt || 0;

    if (!isHomeCard(card)) {
      return;
    }

    var imageContainer = card.querySelector(
      '.service-item__image'
    );

    var nativeTitle = card.querySelector(
      '.service-item__title'
    );

    if (!imageContainer || !nativeTitle) {
      return;
    }

    var service = getServiceData(card);

    if (
      !service &&
      attempt < 5
    ) {

      setTimeout(function () {

        buildCard(
          card,
          attempt + 1
        );

      }, 150);

      return;
    }


    removeOldElements(card);


    /*
      Esta clase será la que controla
      TODO nuestro CSS personalizado.
    */

    card.classList.add(
      'pk-home-service-card'
    );


    var titleData =
      getTitleData(card);

    var durationText =
      getDuration(card);

    var priceText =
      buildPriceText(
        card,
        service
      );


    /* =======================================================
       BADGE
       ======================================================= */

    var badge =
      document.createElement('div');

    badge.className =
      'ota-group-badge';

    badge.textContent =
      'Salida grupal programada';

    imageContainer.appendChild(
      badge
    );


    /* =======================================================
       CUERPO
       ======================================================= */

    var body =
      document.createElement('div');

    body.className =
      'ota-card-body';


    /* TÍTULO */

    var title =
      document.createElement('div');

    title.className =
      'ota-card-title';

    title.textContent =
      titleData.title;

    body.appendChild(title);


    /* SUBTÍTULO */

    if (titleData.subtitle) {

      var subtitle =
        document.createElement('div');

      subtitle.className =
        'ota-card-subtitle';

      subtitle.textContent =
        titleData.subtitle;

      body.appendChild(subtitle);
    }


    /* =======================================================
       META
       ======================================================= */

    var meta =
      document.createElement('div');

    meta.className =
      'ota-card-meta';


    if (priceText) {

      var price =
        document.createElement('div');

      price.className =
        'ota-card-price';

      price.textContent =
        priceText;

      meta.appendChild(price);
    }


    if (durationText) {

      var duration =
        document.createElement('div');

      duration.className =
        'ota-card-duration';

      duration.textContent =
        durationText;

      meta.appendChild(duration);
    }


    body.appendChild(meta);


    /* =======================================================
       CTA
       ======================================================= */

    var cta =
      document.createElement('div');

    cta.className =
      'ota-card-cta';


    var ctaText =
      document.createElement('span');

    ctaText.textContent =
      'Ver fechas y disponibilidad';


    var arrow =
      document.createElement('span');

    arrow.className =
      'ota-card-cta-arrow';

    arrow.textContent = '→';


    cta.appendChild(ctaText);
    cta.appendChild(arrow);

    body.appendChild(cta);


    imageContainer.insertAdjacentElement(
      'afterend',
      body
    );


    card.dataset.peaklineCard =
      'true';
  }


  /* =========================================================
     11 — PROCESAR
     ========================================================= */

  function processAllCards() {

    document
      .querySelectorAll(
        '.service-list .service-item, ' +
        '.vly-services-carousel-track .service-item'
      )
      .forEach(function (card) {

        if (!isHomeCard(card)) {
          return;
        }

        if (
          card.dataset.peaklineCard !==
          'true'
        ) {

          buildCard(
            card,
            0
          );
        }

      });
  }


  /* =========================================================
     12 — INICIO
     ========================================================= */

  function start() {

    setTimeout(
      processAllCards,
      300
    );

  }


  if (
    document.readyState ===
    'loading'
  ) {

    document.addEventListener(
      'DOMContentLoaded',
      start
    );

  } else {

    start();

  }


  /* =========================================================
     13 — CAMBIO DE CATEGORÍAS
     ========================================================= */

  var observer =
    new MutationObserver(
      function () {

        setTimeout(
          processAllCards,
          180
        );

      }
    );


  observer.observe(
    document.body,
    {
      childList: true,
      subtree: true
    }
  );

})();