/**
 * Configuración global del curso.
 * @namespace
 * @property {string} COURSE_CONFIG_URL - Ruta al archivo de configuración JSON del curso.
 * @property {boolean} DEBUG - Habilita/deshabilita el modo de depuración.
 */
window.COURSE_CONFIG = {
  COURSE_CONFIG_URL: 'config.json',
  DEBUG: true,
};

/**
 * Renderiza la paginación mostrando la posición actual dentro del módulo.
 * @function renderPagination
 * @param {number} currentIndex - Índice del slide actual en el array completo.
 * @param {Array<Object>} contentArray - Array completo de slides del curso.
 * @example
 * // Ejemplo de uso:
 * renderPagination(2, courseData.contentArray);
 */
function renderPagination(currentIndex, contentArray) {
  const pageNumber = document.getElementById('coursenav-page-number');
  const totalPages = document.getElementById('coursenav-total-pages');

  if (!Array.isArray(contentArray)) return;
  // Gestionar visibilidad de menús primero
  manageMenuVisibility(currentIndex, contentArray);
  // Obtener el módulo actual basado en el slide actual
  const currentSlide = contentArray[currentIndex];
  if (!currentSlide) return;

  // Filtrar todos los slides del mismo módulo
  const moduleSlides = contentArray.filter((slide) => slide.moduleTitle === currentSlide.moduleTitle);

  // Encontrar la posición del slide actual dentro del módulo
  const moduleSlideIndex = moduleSlides.findIndex((slide) => slide.content === currentSlide.content);

  if (pageNumber) pageNumber.textContent = moduleSlideIndex + 1;
  if (totalPages) totalPages.textContent = ' / ' + moduleSlides.length;
  //Navegación personalizada
  updateNavButtons(moduleSlideIndex, moduleSlides);
}
/**
 * Actualiza el estado (habilitado/deshabilitado) de los botones de navegación
 * del módulo (anterior/siguiente).
 *
 * Esta función deshabilita el botón "siguiente" si el usuario está en la última
 * diapositiva del módulo y el botón "anterior" si está en la primera.
 * Sin embargo, si el curso está en modo de depuración (`CourseNav.isDebug()` es true),
 * los botones permanecerán habilitados, permitiendo la navegación libre.
 *
 * @function updateNavButtons
 * @param {number} moduleSlideIndex - El índice de base cero de la diapositiva actual dentro de su módulo.
 * @param {Array<Object>} moduleSlides - Un array de los objetos de diapositiva que pertenecen al módulo actual.
 */
function updateNavButtons(moduleSlideIndex, moduleSlides) {
  const nextBtn = document.getElementById('coursenav-next-btn');
  const prevBtn = document.getElementById('coursenav-prev-btn');

  if (!nextBtn || !prevBtn) return;

  const isLastSlide = moduleSlideIndex + 1 === moduleSlides.length;
  const isFirstSlide = moduleSlideIndex === 0;
  const isDebugMode = CourseNav.isDebug();

  nextBtn.classList.toggle('disabled', isLastSlide && !isDebugMode);
  prevBtn.classList.toggle('disabled', isFirstSlide && !isDebugMode);
}
/**
 * Gestiona la visibilidad de los menús del curso en la barra de navegación.
 *
 * Esta función muestra u oculta dinámicamente los menús secundarios
 * (`ul.course-menu`) basándose en el módulo del slide actual. Se asume que
 * el primer menú es el principal y siempre debe estar visible, mientras que
 * los menús subsecuentes son específicos de cada módulo y solo se muestran
 * cuando el usuario está navegando en dicho módulo.
 *
 * @function manageMenuVisibility
 * @param {number} currentIndex - El índice del slide actual en el array global de contenido.
 * @param {Array<Object>} contentArray - El array completo de objetos de slide del curso.
 */
function manageMenuVisibility(currentIndex, contentArray) {
  const courseMenus = document.querySelectorAll('#coursenav-main-menu > ul.course-menu');
  if (!courseMenus.length) return;

  // El primer menú siempre está visible.
  courseMenus[0].style.display = 'block';

  // Si no hay contenido, ocultar los demás menús.
  if (!Array.isArray(contentArray) || !contentArray.length) {
    for (let i = 1; i < courseMenus.length; i++) {
      courseMenus[i].style.display = 'none';
    }
    return;
  }

  const currentSlide = contentArray[currentIndex];
  // Si el slide actual no existe o no tiene un título de módulo, ocultar los demás.
  if (!currentSlide?.moduleTitle) {
    for (let i = 1; i < courseMenus.length; i++) {
      courseMenus[i].style.display = 'none';
    }
    return;
  }

  const currentModuleTitle = currentSlide.moduleTitle;

  for (let i = 1; i < courseMenus.length; i++) {
    const menuItems = Array.from(courseMenus[i].querySelectorAll('.coursenav-link'));
    const shouldShow = menuItems.some((item) => {
      const itemIndex = parseInt(item.dataset.coursenavindex);
      return itemIndex >= 0 && contentArray[itemIndex]?.moduleTitle === currentModuleTitle;
    });
    courseMenus[i].style.display = shouldShow ? 'block' : 'none';
  }
}

/**
 * Desplaza la ventana hasta la parte superior de un elemento.
 * @function scrollToElementTop
 * @param {string} selector - Selector CSS del elemento objetivo.
 * @param {Object} [options={}] - Opciones de scroll.
 * @param {string} [options.behavior="smooth"] - Comportamiento del scroll ('auto' o 'smooth').
 * @param {string} [options.block="start"] - Alineación vertical ('start', 'center', 'end' o 'nearest').
 * @param {string} [options.inline="nearest"] - Alineación horizontal ('start', 'center', 'end' o 'nearest').
 * @example
 * // Ejemplo de uso:
 * scrollToElementTop('#main-content', { behavior: 'smooth', block: 'start' });
 */
function scrollToElementTop(selector, options = {}) {
  const defaults = { behavior: 'smooth', block: 'start', inline: 'nearest' };
  const opts = Object.assign(defaults, options);
  const el = document.querySelector(selector);
  if (el) el.scrollIntoView(opts);
}

/**
 * Observador de intersección para animar elementos cuando son visibles en el viewport.
 * @function animateOnScroll
 * @param {string} selector - Selector de los elementos a observar.
 * @param {string} animationClass - Clase de animación de Animate.css (ej. 'animate__fadeInUp').
 * @param {Object} [options={}] - Opciones de configuración.
 * @param {number} [options.threshold=0.1] - Umbral de visibilidad (0-1).
 * @param {boolean} [options.animateOnce=true] - Si es true, la animación solo se ejecuta una vez.
 * @param {string} [options.prefix='animate__animated'] - Prefijo para clases de animación.
 * @returns {IntersectionObserver} Instancia del observador.
 * @example
 * // Ejemplo de uso:
 * animateOnScroll('.animar', 'animate__fadeIn', { threshold: 0.2 });
 */
function animateOnScroll(selector, animationClass, options = {}) {
  const { threshold = 0.1, animateOnce = true, prefix = 'animate__animated' } = options;

  const cb = (entries, observer) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add(prefix, animationClass);
        if (animateOnce) observer.unobserve(entry.target);
      } else if (!animateOnce) {
        entry.target.classList.remove(prefix, animationClass);
      }
    });
  };

  const observer = new IntersectionObserver(cb, { threshold });
  document.querySelectorAll(selector).forEach((el) => observer.observe(el));
  return observer;
}

function scaleWrapCourseContent() {
  const content = document.querySelector('.wrap-course-content');
  if (!content) return;

  const ww = window.innerWidth;
  const wh = window.innerHeight;

  // Breakpoint a 1500px
  let baseWidth, baseHeight;

  if (ww < 1500) {
    // Menor a 1500px: usar 1366x768
    baseWidth = 1366;
    baseHeight = 768;
  } else {
    // 1500px o más: usar 1920x1080
    baseWidth = 1920;
    baseHeight = 1080;
  }

  // Escala simple
  const scale = Math.min(ww / baseWidth, wh / baseHeight);

  content.style.transform = `scale(${scale})`;
  content.style.transformOrigin = 'top left';
  content.style.width = baseWidth + 'px';
  content.style.height = baseHeight + 'px';
  content.style.position = 'absolute';
  content.style.left = (ww - baseWidth * scale) / 2 + 'px';
  content.style.top = (wh - baseHeight * scale) / 2 + 'px';
  content.style.overflow = 'hidden';
  content.style.zIndex = '1';
}

/**
 * Renderiza un stepper visual que muestra el progreso del curso.
 * @function renderStepper
 * @param {HTMLElement|string} stepperEl - Elemento o selector del contenedor del stepper.
 * @param {number} progressPercent - Porcentaje de progreso (0-100).
 * @param {HTMLElement|string} mobileEl - Elemento o selector del indicador móvil.
 * @param {number} [stepsCount=5] - Número de pasos visibles en el stepper.
 * @throws {Error} Si los elementos no son válidos.
 * @example
 * // Ejemplo de uso:
 * renderStepper('#stepper', 75, '#step-movil', 4);
 */
function renderStepper(stepperEl, progressPercent, mobileEl, stepsCount = 5) {
  // Validación y obtención de elementos
  if (typeof stepperEl === 'string') stepperEl = document.querySelector(stepperEl);
  if (typeof mobileEl === 'string') mobileEl = document.querySelector(mobileEl);
  if (!(stepperEl instanceof HTMLElement) || !(mobileEl instanceof HTMLElement)) {
    throw new Error('renderStepper: elementos inválidos.');
  }

  // Limpiar contenido previo
  stepperEl.querySelectorAll('.step').forEach((el) => el.remove());

  // Calcular posiciones de los pasos
  const stepPercents = Array.from({ length: stepsCount }, (_, i) => (i / (stepsCount - 1)) * 100);

  // Determinar paso actual
  const currentIndex = stepPercents
    .map((p, i) => ({ p, i }))
    .filter(({ p }) => p <= progressPercent)
    .pop().i;

  // Crear elementos de los pasos
  stepPercents.forEach((pct, i) => {
    const step = document.createElement('div');
    step.classList.add('step');
    if (i < currentIndex) step.classList.add('completed');
    if (i === currentIndex) {
      step.classList.add('completed');
      step.setAttribute('data-label', Math.round(pct) + '%');
    }
    stepperEl.appendChild(step);
  });

  // Actualizar estilos y posición
  stepperEl.style.setProperty('--pct', progressPercent + '%');

  const halfMobile = mobileEl.offsetWidth;
  mobileEl.style.left = `calc(${progressPercent}% - ${halfMobile}px)`;
  mobileEl.setAttribute('data-label', progressPercent + '%');
}

/**
 * Navega al primer slide que tenga el título "Menús de la herramienta".
 *
 * Esta función busca en todo el contenido del curso y se desplaza a la primera
 * diapositiva que coincida con ese título específico y modulo actual de donde es invocada la funcion. Es útil para crear
 * accesos directos a secciones clave.
 * @function gotoFirstMenuToolSlide
 * @example
 * // Se puede vincular a un botón:
 * // document.getElementById('mi-boton').addEventListener('click', gotoFirstMenuToolSlide);
 */
function gotoFirstMenuToolSlide() {
  const contentArray = CourseNav.getCourseContentArray();
  const targetTitle = 'Menús de la herramienta';
  const currentSlide = CourseNav.getCurrentSlide();
  // Filtrar todos los slides del mismo módulo
  const targetIndex = contentArray.findIndex(
    (slide) => slide.title === targetTitle && slide.moduleTitle === currentSlide.moduleTitle
  );

  if (targetIndex !== -1) {
    CourseNav.gotoSlide(targetIndex);
  } else {
    console.warn(`No se encontró ningún slide con el título '${targetTitle}'.`);
  }
}

/**
 * Configura los event listeners cuando el DOM está completamente cargado.
 * @event DOMContentLoaded
 */
document.addEventListener('DOMContentLoaded', () => {
  // Escalado inicial y continuo
  scaleWrapCourseContent();
  setTimeout(scaleWrapCourseContent, 100);

  // Escalado en redimensionamiento con debounce
  let resizeTimeout;
  window.addEventListener('resize', () => {
    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(scaleWrapCourseContent, 50);
  });

  // Escalado en cambio de orientación (móviles/tablets)
  window.addEventListener('orientationchange', () => {
    setTimeout(scaleWrapCourseContent, 200);
  });

  // Escalado cuando cambia la visibilidad (cambio de pestaña)
  document.addEventListener('visibilitychange', () => {
    if (!document.hidden) {
      setTimeout(scaleWrapCourseContent, 100);
    }
  });

  /**
   * Evento antes de cambiar de slide.
   * @event beforeSlideChange
   * @property {Object} detail - Detalles del evento.
   * @property {number} detail.currentIndex - Índice del slide actual.
   * @property {Array} detail.contentArray - Array completo de contenido.
   */
  document.body.addEventListener('beforeSlideChange', (e) => {
    console.log('Antes de cambiar de slide:', e.detail);
  });

  /**
   * Evento al cambiar de slide.
   * @event slideChange
   * @property {Object} detail - Detalles del evento.
   * @property {number} detail.slideIndex - Índice del nuevo slide.
   * @property {Array} detail.contentArray - Array completo de contenido.
   */
  document.body.addEventListener('slideChange', (e) => {
    if (e.detail && typeof e.detail.slideIndex === 'number' && Array.isArray(e.detail.contentArray)) {
      renderPagination(e.detail.slideIndex, e.detail.contentArray);
      console.log(e.detail.contentArray[e.detail.slideIndex].content);
      const contentArray = e.detail.contentArray;
      const targetTitle = 'Menús de la herramienta';
      const currentSlide = CourseNav.getCurrentSlide();
      // Filtrar todos los slides del mismo módulo
      const targetIndex = contentArray.findIndex(
        (slide) => slide.title === targetTitle && slide.moduleTitle === currentSlide.moduleTitle
      );
      const btn = document.getElementById('coursenav-other-btn');
      if (!btn) return;
      if (targetIndex !== -1) {
        btn.classList.remove('disabled');
      } else {
        btn.classList.add('disabled');
      }
    }

    const titleSlide = document.getElementById('coursenav-course-title');
    if (titleSlide) {
      const slide = e.detail.contentArray[e.detail.slideIndex];
      const moduleTitle = slide.moduleTitle ? slide.moduleTitle + ' | ' : '';
      const title = slide.title || 'Sin título';
      titleSlide.textContent = moduleTitle + title;
    }

    const stepper = document.getElementById('stepper');
    const movil = document.getElementById('step-movil');
    const progreso = CourseNav.getProgressPercent(true);
    renderStepper(stepper, progreso, movil);
  });

  /**
   * Evento al completar un slide.
   * @event slideCompleted
   * @property {Object} detail - Detalles del evento.
   */
  document.body.addEventListener('slideCompleted', (e) => {
    console.log('Slide completado:', e.detail);
    const stepper = document.getElementById('stepper');
    const movil = document.getElementById('step-movil');
    const progreso = CourseNav.getProgressPercent(true);
    renderStepper(stepper, progreso, movil);
    renderPagination(e.detail.slideIndex, CourseNav.getCourseContentArray());
  });

  // Event listener para botón personalizado
  const customButtonEvent = document.getElementById('coursenav-other-btn');
  if (customButtonEvent) {
    customButtonEvent.addEventListener('click', () => {
      console.log('Botón personalizado clickeado');
      gotoFirstMenuToolSlide();
    });
  }
});

// Escalar contenido al cargar y redimensionar
window.addEventListener('DOMContentLoaded', () => scaleWrapCourseContent());
window.addEventListener('resize', () => scaleWrapCourseContent());
