/**
* Template Name: FolioOne
* Template URL: https://bootstrapmade.com/folioone-bootstrap-portfolio-website-template/
* Updated: Aug 23 2025 with Bootstrap v5.3.7
* Author: BootstrapMade.com
* License: https://bootstrapmade.com/license/
*/

(function () {
  "use strict";

  /**
   * Apply .scrolled class to the body as the page is scrolled down
   */
  function toggleScrolled() {
    const selectBody = document.querySelector('body');
    const selectHeader = document.querySelector('#header');
    if (!selectHeader.classList.contains('scroll-up-sticky') && !selectHeader.classList.contains('sticky-top') && !selectHeader.classList.contains('fixed-top')) return;
    window.scrollY > 100 ? selectBody.classList.add('scrolled') : selectBody.classList.remove('scrolled');
  }

  document.addEventListener('scroll', toggleScrolled);
  window.addEventListener('load', toggleScrolled);

  /**
   * Mobile nav toggle
   */
  const mobileNavToggleBtn = document.querySelector('.mobile-nav-toggle');

  function mobileNavToogle() {
    document.querySelector('body').classList.toggle('mobile-nav-active');
    mobileNavToggleBtn.classList.toggle('bi-list');
    mobileNavToggleBtn.classList.toggle('bi-x');
  }
  if (mobileNavToggleBtn) {
    mobileNavToggleBtn.addEventListener('click', mobileNavToogle);
  }

  /**
   * Hide mobile nav on same-page/hash links
   */
  document.querySelectorAll('#navmenu a').forEach(navmenu => {
    navmenu.addEventListener('click', () => {
      if (document.querySelector('.mobile-nav-active')) {
        mobileNavToogle();
      }
    });

  });

  /**
   * Toggle mobile nav dropdowns
   */
  document.querySelectorAll('.navmenu .toggle-dropdown').forEach(navmenu => {
    navmenu.addEventListener('click', function (e) {
      e.preventDefault();
      this.parentNode.classList.toggle('active');
      this.parentNode.nextElementSibling.classList.toggle('dropdown-active');
      e.stopImmediatePropagation();
    });
  });

  /**
   * Preloader
   */
  const preloader = document.querySelector('#preloader');
  if (preloader) {
    window.addEventListener('load', () => {
      preloader.remove();
    });
  }

  /**
   * Scroll top button
   */
  let scrollTop = document.querySelector('.scroll-top');

  function toggleScrollTop() {
    if (scrollTop) {
      window.scrollY > 100 ? scrollTop.classList.add('active') : scrollTop.classList.remove('active');
    }
  }
  scrollTop.addEventListener('click', (e) => {
    e.preventDefault();
    window.scrollTo({
      top: 0,
      behavior: 'smooth'
    });
  });

  window.addEventListener('load', toggleScrollTop);
  document.addEventListener('scroll', toggleScrollTop);

  /**
   * Init typed.js
   */
  const selectTyped = document.querySelector('.typed');
  if (selectTyped && typeof Typed !== 'undefined') {
    let typed_strings = selectTyped.getAttribute('data-typed-items');
    typed_strings = typed_strings.split(',');
    new Typed('.typed', {
      strings: typed_strings,
      loop: true,
      typeSpeed: 100,
      backSpeed: 50,
      backDelay: 2000
    });
  }

  /**
   * Animate the skills items on reveal
   */
  let skillsAnimation = document.querySelectorAll('.skills-animation');
  if (skillsAnimation.length > 0 && typeof Waypoint !== 'undefined') {
    skillsAnimation.forEach((item) => {
      new Waypoint({
        element: item,
        offset: '80%',
        handler: function (direction) {
          let progress = item.querySelectorAll('.progress .progress-bar');
          progress.forEach(el => {
            el.style.width = el.getAttribute('aria-valuenow') + '%';
          });
        }
      });
    });
  }

  /**
   * Initiate Pure Counter
   */
  if (typeof PureCounter !== 'undefined') {
    new PureCounter();
  }

  /**
   * Init swiper sliders
   */
  function initSwiper() {
    if (typeof Swiper !== 'undefined') {
      document.querySelectorAll(".init-swiper").forEach(function (swiperElement) {
        let config = JSON.parse(
          swiperElement.querySelector(".swiper-config").innerHTML.trim()
        );

        if (swiperElement.classList.contains("swiper-tab")) {
          initSwiperWithCustomPagination(swiperElement, config);
        } else {
          new Swiper(swiperElement, config);
        }
      });
    }
  }

  window.addEventListener("load", initSwiper);

  /**
   * Init isotope layout and filters
   */
  if (typeof Isotope !== 'undefined' && typeof imagesLoaded !== 'undefined') {
    document.querySelectorAll('.isotope-layout').forEach(function (isotopeItem) {
      let layout = isotopeItem.getAttribute('data-layout') ?? 'masonry';
      let filter = isotopeItem.getAttribute('data-default-filter') ?? '*';
      let sort = isotopeItem.getAttribute('data-sort') ?? 'original-order';

      let initIsotope;
      imagesLoaded(isotopeItem.querySelector('.isotope-container'), function () {
        initIsotope = new Isotope(isotopeItem.querySelector('.isotope-container'), {
          itemSelector: '.isotope-item',
          layoutMode: layout,
          filter: filter,
          sortBy: sort
        });
      });

      isotopeItem.querySelectorAll('.isotope-filters li').forEach(function (filters) {
        filters.addEventListener('click', function () {
          isotopeItem.querySelector('.isotope-filters .filter-active').classList.remove('filter-active');
          this.classList.add('filter-active');
          initIsotope.arrange({
            filter: this.getAttribute('data-filter')
          });
          if (typeof aosInit === 'function') {
            aosInit();
          }
        }, false);
      });

    });
  }

  /**
   * Initiate glightbox
   */
  if (typeof GLightbox !== 'undefined') {
    const glightbox = GLightbox({
      selector: '.glightbox'
    });
  }

})();

/**
 * UX Enhancements - Custom Cursor (Optimized)
 */
(function () {
  // Only enable on non-touch devices and desktops (not mobile)
  if (window.matchMedia("(hover: hover) and (pointer: fine)").matches && window.innerWidth >= 1024) {
    window.addEventListener('load', function () {
      const cursor = document.createElement('div');
      cursor.className = 'custom-cursor';
      const cursorFollower = document.createElement('div');
      cursorFollower.className = 'custom-cursor-follower';

      document.body.appendChild(cursor);
      document.body.appendChild(cursorFollower);

      let mouseX = 0, mouseY = 0;
      let followerX = 0, followerY = 0;

      // Use transform for better performance
      document.addEventListener('mousemove', (e) => {
        mouseX = e.clientX;
        mouseY = e.clientY;
        cursor.style.transform = `translate(${mouseX}px, ${mouseY}px)`;
      });

      // Smooth follower animation with requestAnimationFrame
      function animateFollower() {
        const distX = mouseX - followerX;
        const distY = mouseY - followerY;

        followerX += distX * 0.15; // Augmenté de 0.1 à 0.15 pour plus de réactivité
        followerY += distY * 0.15;

        cursorFollower.style.transform = `translate(${followerX}px, ${followerY}px)`;

        requestAnimationFrame(animateFollower);
      }
      animateFollower();

      // Add hover effects for interactive elements (avec délégation d'événements)
      document.addEventListener('mouseenter', (e) => {
        if (e.target.matches('a, button, .btn, input, textarea, select')) {
          cursor.classList.add('hover');
          cursorFollower.classList.add('hover');
        }
      }, true);

      document.addEventListener('mouseleave', (e) => {
        if (e.target.matches('a, button, .btn, input, textarea, select')) {
          cursor.classList.remove('hover');
          cursorFollower.classList.remove('hover');
        }
      }, true);
    });
  }
})();

/**
 * UX Enhancements - Scroll Progress Indicator (Optimized with RAF)
 */
(function () {
  const progressBar = document.createElement('div');
  progressBar.className = 'scroll-progress';
  document.body.appendChild(progressBar);

  let ticking = false;

  function updateScrollProgress() {
    const windowHeight = window.innerHeight;
    const documentHeight = document.documentElement.scrollHeight;
    const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
    const scrollPercent = Math.min((scrollTop / (documentHeight - windowHeight)) * 100, 100);

    progressBar.style.width = scrollPercent + '%';
    ticking = false;
  }

  window.addEventListener('scroll', function () {
    if (!ticking) {
      window.requestAnimationFrame(updateScrollProgress);
      ticking = true;
    }
  }, { passive: true });

  window.addEventListener('load', updateScrollProgress);
})();

/**
 * UX Enhancements - Text Reveal on Scroll (Optimized with RAF)
 */
(function () {
  window.addEventListener('load', function () {
    const revealElements = document.querySelectorAll('.reveal-text');

    if (revealElements.length === 0) return;

    let ticking = false;

    function checkReveal() {
      revealElements.forEach(el => {
        if (!el.classList.contains('revealed')) {
          const elementTop = el.getBoundingClientRect().top;
          const elementVisible = 150;

          if (elementTop < window.innerHeight - elementVisible) {
            el.classList.add('revealed');
          }
        }
      });
      ticking = false;
    }

    window.addEventListener('scroll', function () {
      if (!ticking) {
        window.requestAnimationFrame(checkReveal);
        ticking = true;
      }
    }, { passive: true });

    checkReveal(); // Initial check
  });
})();

/**
 * UX Enhancements - Smooth Parallax Effect (Optimized with RAF)
 */
(function () {
  window.addEventListener('load', function () {
    const parallaxElements = document.querySelectorAll('.parallax-bg');

    if (parallaxElements.length === 0) return;

    let ticking = false;

    function updateParallax() {
      const scrolled = window.pageYOffset;
      parallaxElements.forEach(el => {
        const rate = scrolled * 0.3;
        el.style.transform = `translate3d(0, ${rate}px, 0)`;
      });
      ticking = false;
    }

    window.addEventListener('scroll', function () {
      if (!ticking) {
        window.requestAnimationFrame(updateParallax);
        ticking = true;
      }
    }, { passive: true });
  });
})();

/**
 * UX Enhancements - Enhanced Card Tilt Effect (Subtle 3D) - Optimized
 */
(function () {
  window.addEventListener('load', function () {
    const tiltElements = document.querySelectorAll('.service-item, .portfolio-item');

    if (tiltElements.length === 0) return; // Exit if no elements

    tiltElements.forEach(el => {
      let ticking = false;

      el.addEventListener('mousemove', (e) => {
        if (!ticking) {
          window.requestAnimationFrame(() => {
            const rect = el.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;

            const centerX = rect.width / 2;
            const centerY = rect.height / 2;

            const rotateX = ((y - centerY) / centerY) * 2; // Réduit à 2 pour plus de subtilité
            const rotateY = ((centerX - x) / centerX) * 2;

            // Préserve le translateY existant et ajoute la rotation 3D
            const baseTranslateY = el.classList.contains('service-item') ? -5 : -10;
            el.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateY(${baseTranslateY}px)`;

            ticking = false;
          });
          ticking = true;
        }
      });

      el.addEventListener('mouseleave', () => {
        // Remet la transformation de base au survol (définie dans le CSS)
        el.style.transform = '';
      });
    });
  });
})();

/**
 * UX Enhancements - Improved AOS Configuration (Optimized for Performance)
 */
function aosInit() {
  if (typeof AOS !== 'undefined') {
    AOS.init({
      duration: 400, // Encore plus rapide pour éviter le "lag" visuel
      easing: 'ease-out-cubic', // Easing plus dynamique
      once: true,
      mirror: false,
      offset: 50, // Déclenchement très tôt
      delay: 0,
      anchorPlacement: 'top-bottom',
      disable: function () {
        // Désactiver sur mobile pour meilleures performances
        return window.innerWidth < 768;
      }
    });
  }
}
window.addEventListener('load', aosInit);

/**
 * UX Enhancements - Smooth Scroll Enhancement (Optimized)
 */
window.addEventListener('load', function () {
  document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function (e) {
      const href = this.getAttribute('href');
      if (href !== '#' && href !== '#scroll-top') {
        const target = document.querySelector(href);
        if (target) {
          e.preventDefault();
          target.scrollIntoView({
            behavior: 'smooth',
            block: 'start'
          });
        }
      }
    });
  });
});

/**
 * UX Enhancements - Add Loading States to Buttons (Optimized)
 */
/**
 * UX Enhancements - Add Loading States to Buttons (Optimized)
 * REMOVED: Interferes with Formspree submission
 */
// window.addEventListener('load', function () {
//   const submitButtons = document.querySelectorAll('button[type="submit"], .btn[type="submit"]');
//
//   submitButtons.forEach(btn => {
//     btn.addEventListener('click', function (e) {
//       if (this.form && this.form.checkValidity()) {
//         const originalText = this.innerHTML;
//         this.innerHTML = '<i class="bi bi-hourglass-split"></i> Envoi en cours...';
//         this.disabled = true;
//
//         // Reset after 3 seconds (adjust based on your needs)
//         setTimeout(() => {
//           this.innerHTML = originalText;
//           this.disabled = false;
//         }, 3000);
//       }
//     });
//   });
// });

/**
 * UX Enhancements - Ambient Light Effects with Parallax
 */
(function () {
  // Only enable on desktop for performance
  if (window.innerWidth >= 768) {
    window.addEventListener('load', function () {
      // Create ambient lights container
      const ambientLights = document.createElement('div');
      ambientLights.className = 'ambient-lights';
      document.body.insertBefore(ambientLights, document.body.firstChild);

      // Create light orbs
      for (let i = 1; i <= 4; i++) {
        const orb = document.createElement('div');
        orb.className = `light-orb light-orb-${i}`;
        ambientLights.appendChild(orb);
      }

      // Create light rays
      for (let i = 1; i <= 3; i++) {
        const ray = document.createElement('div');
        ray.className = `light-ray light-ray-${i}`;
        ambientLights.appendChild(ray);
      }

      // Create light particles (random positions)
      for (let i = 0; i < 20; i++) {
        const particle = document.createElement('div');
        particle.className = 'light-particle';
        particle.style.top = Math.random() * 100 + '%';
        particle.style.left = Math.random() * 100 + '%';
        particle.style.animationDelay = Math.random() * 3 + 's';
        ambientLights.appendChild(particle);
      }

      // Create gradient spotlights
      for (let i = 1; i <= 2; i++) {
        const spotlight = document.createElement('div');
        spotlight.className = `gradient-spotlight gradient-spotlight-${i}`;
        ambientLights.appendChild(spotlight);
      }

      // Parallax effect on scroll (optimized with RAF and throttling)
      const orbs = document.querySelectorAll('.light-orb');
      const rays = document.querySelectorAll('.light-ray');
      const spotlights = document.querySelectorAll('.gradient-spotlight');
      let ticking = false;

      function updateLightParallax() {
        const scrollY = window.pageYOffset;

        // Orbs: slow parallax (different speeds)
        orbs.forEach((orb, index) => {
          const speed = 0.1 + (index * 0.05); // Different speed for each orb
          const yPos = scrollY * speed;
          orb.style.transform = `translateY(${yPos}px)`;
        });

        // Rays: medium parallax
        rays.forEach((ray, index) => {
          const speed = 0.15 + (index * 0.03);
          const yPos = scrollY * speed;
          const rotation = 15 + (index * 5);
          ray.style.transform = `translateY(${yPos}px) rotate(${rotation}deg)`;
        });

        // Spotlights: faster parallax
        spotlights.forEach((spotlight, index) => {
          const speed = 0.25 + (index * 0.1);
          const yPos = scrollY * speed;
          if (index === 0) {
            spotlight.style.transform = `translate(-50%, ${yPos}px)`;
          } else {
            spotlight.style.transform = `translateY(${yPos}px)`;
          }
        });

        ticking = false;
      }

      window.addEventListener('scroll', function () {
        if (!ticking) {
          window.requestAnimationFrame(updateLightParallax);
          ticking = true;
        }
      }, { passive: true });

      // Initial position
      updateLightParallax();
    });
  }
})();

/* Matrix-like background animation confined to header canvases (slower) */
(function () {
  // Only run on larger screens to avoid perf issues on mobile
  function shouldEnableMatrix() {
    // Force-enable on Services page regardless of viewport width
    if (document.body && document.body.classList.contains('services-page')) {
      return true;
    }
    // Otherwise keep default threshold to avoid perf issues on small screens
    return window.innerWidth >= 900;
  }

  const canvases = Array.from(document.querySelectorAll('.matrix-bg-header'));
  if (!canvases.length) return;

  const instances = [];

  const chars = '01<>/{}[]()\u25A0\u25A1'.split('');

  function createInstance(canvas) {
    const ctx = canvas.getContext('2d');
    let width = 0;
    let height = 0;
    let columns = [];
    let animationId = null;

    function init() {
      const dpr = Math.max(1, window.devicePixelRatio || 1);
      const rect = canvas.parentElement.getBoundingClientRect();
      width = canvas.width = Math.floor(rect.width * dpr);
      // limit canvas height to header height
      height = canvas.height = Math.floor(rect.height * dpr);
      canvas.style.width = rect.width + 'px';
      canvas.style.height = rect.height + 'px';

      // slightly larger font for clarity, but scaled by DPR
      const fontSize = Math.max(10, Math.floor((rect.width / 160) * dpr));
      ctx.font = fontSize + 'px monospace';
      ctx.textBaseline = 'top';

      const columnCount = Math.ceil(width / fontSize);
      columns = new Array(columnCount).fill(0).map(() => ({ y: Math.random() * -height }));
      return fontSize;
    }

    function draw() {
      // A darker translucent fill to keep effect subtle on header
      ctx.fillStyle = 'rgba(16,26,32,0.35)';
      ctx.fillRect(0, 0, width, height);

      const computed = getComputedStyle(document.documentElement).getPropertyValue('--matrix-pale-blue').trim() || '#8fcbe9';
      ctx.fillStyle = computed;

      // Slightly increase text opacity to make the falling characters a bit more visible
      // Use save/restore so only the text rendering is affected (background fill stays same)
      const textAlpha = 0.78; // small increase from default for better visibility
      ctx.save();
      ctx.globalAlpha = textAlpha;

      const fontSizeMatch = ctx.font.match(/(\d+)px/);
      const fontSize = fontSizeMatch ? parseInt(fontSizeMatch[1], 10) : 12;

      // slower motion: smaller increments
      for (let i = 0; i < columns.length; i += 1) {
        const col = columns[i];
        // render only rarely to greatly reduce density (slower effect)
        if (Math.random() < 0.88) continue;
        const text = chars[Math.floor(Math.random() * chars.length)];
        const x = i * fontSize;
        ctx.fillText(text, x, col.y);
        // much slower falling speed and subtle randomness
        col.y += (fontSize * 0.18) + Math.random() * (fontSize * 0.08);
        if (col.y > height + Math.random() * 200) {
          col.y = Math.random() * -height * 0.6;
        }
      }

      // restore alpha after drawing text so other canvas ops are unaffected
      ctx.restore();

      animationId = requestAnimationFrame(draw);
    }

    function start() {
      cancelAnimationFrame(animationId);
      init();
      draw();
    }

    function stop() {
      if (animationId) cancelAnimationFrame(animationId);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    }

    return { start, stop, init };
  }

  canvases.forEach(c => instances.push(createInstance(c)));

  function startAll() {
    if (!shouldEnableMatrix()) return;
    console.debug('[matrix] startAll: starting matrix instances');
    instances.forEach(i => i.start());
  }

  function stopAll() {
    console.debug('[matrix] stopAll: stopping matrix instances');
    instances.forEach(i => i.stop());
  }

  // Pause on tab hidden
  document.addEventListener('visibilitychange', function () {
    if (document.hidden) stopAll(); else startAll();
  });

  let resizeTimer = null;
  window.addEventListener('resize', function () {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function () {
      if (shouldEnableMatrix()) startAll(); else stopAll();
    }, 300);
  });

  window.addEventListener('load', function () {
    if (shouldEnableMatrix()) startAll();
    else console.debug('[matrix] load: matrix disabled by shouldEnableMatrix() (width=' + window.innerWidth + ')');
  });

})();

/**
 * Light/Dark Mode Toggle
 */
(function () {
  const body = document.body;
  const toggleBtn = document.createElement('button');
  toggleBtn.className = 'theme-toggle-btn';
  toggleBtn.innerHTML = '<i class="bi bi-moon-stars-fill"></i>';
  toggleBtn.setAttribute('aria-label', 'Toggle theme');

  // Style the button (fixed position)
  Object.assign(toggleBtn.style, {
    position: 'fixed',
    bottom: '20px',
    right: '20px',
    zIndex: '9999',
    width: '50px',
    height: '50px',
    borderRadius: '50%',
    border: 'none',
    backgroundColor: 'var(--accent-color)',
    color: '#fff',
    fontSize: '1.2rem',
    cursor: 'pointer',
    boxShadow: '0 4px 15px rgba(0,0,0,0.3)',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    transition: 'all 0.3s ease'
  });

  // Hover effect
  toggleBtn.addEventListener('mouseenter', () => {
    toggleBtn.style.transform = 'scale(1.1)';
  });
  toggleBtn.addEventListener('mouseleave', () => {
    toggleBtn.style.transform = 'scale(1)';
  });

  document.body.appendChild(toggleBtn);

  function setLightMode(isLight) {
    if (isLight) {
      body.classList.add('light-mode');
      toggleBtn.innerHTML = '<i class="bi bi-sun-fill"></i>';
    } else {
      body.classList.remove('light-mode');
      toggleBtn.innerHTML = '<i class="bi bi-moon-stars-fill"></i>';
    }
  }

  // Check preference or time
  const savedTheme = localStorage.getItem('theme');
  if (savedTheme) {
    setLightMode(savedTheme === 'light');
  } else {
    const hour = new Date().getHours();
    // Light mode between 00:00 and 17:00
    if (hour < 17) {
      setLightMode(true);
    }
  }

  // Toggle event
  toggleBtn.addEventListener('click', () => {
    const isLight = body.classList.contains('light-mode');
    setLightMode(!isLight);
    localStorage.setItem('theme', !isLight ? 'light' : 'dark');
  });

  /**
   * UX Enhancements - Smooth Page Transitions
   */
  document.addEventListener('DOMContentLoaded', () => {
    const links = document.querySelectorAll('a:not([href^="#"]):not([target="_blank"]):not([href^="mailto:"]):not([href^="tel:"])');

    links.forEach(link => {
      link.addEventListener('click', (e) => {
        const href = link.getAttribute('href');

        // Check if it's a valid internal link
        if (href && !href.startsWith('#') && !href.startsWith('javascript:')) {
          e.preventDefault();
          document.body.classList.add('fade-out');

          setTimeout(() => {
            window.location.href = href;
          }, 300); // Match CSS transition duration
        }
      });
    });
  });

})();