/* ── Matrix Rain ─────────────────────────────────── */
(function () {
  const canvas = document.getElementById('matrix-canvas');
  if (!canvas) return;
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  const ctx   = canvas.getContext('2d');
  const CHARS = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789ABCDEF<>/\\|{}[]$#@!';
  const FS    = 14;
  let cols, drops, raf;

  function init() {
    canvas.width  = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
    cols  = Math.floor(canvas.width / FS) + 1;
    drops = Array.from({ length: cols }, () => Math.random() * -(canvas.height / FS));
  }

  function tick() {
    const light = document.documentElement.classList.contains('theme-light');
    ctx.fillStyle = light ? 'rgba(240,244,248,0.07)' : 'rgba(6,11,16,0.055)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.font = `${FS}px "JetBrains Mono", monospace`;

    for (let i = 0; i < cols; i++) {
      const char = CHARS[Math.floor(Math.random() * CHARS.length)];
      // Occasional bright green "head", otherwise purple
      ctx.fillStyle = Math.random() > 0.96
        ? (light ? '#008f5a' : '#00ff88')
        : (light ? '#7c3aed' : '#a855f7');
      ctx.fillText(char, i * FS, drops[i] * FS);

      if (drops[i] * FS > canvas.height && Math.random() > 0.975) {
        drops[i] = Math.random() * -20;
      }
      drops[i] += 0.5;
    }
    raf = requestAnimationFrame(tick);
  }

  init();
  window.addEventListener('resize', () => { cancelAnimationFrame(raf); init(); tick(); }, { passive: true });
  document.addEventListener('visibilitychange', () => {
    if (document.hidden) cancelAnimationFrame(raf); else tick();
  });
  tick();
})();

/* ── Hero Glitch ─────────────────────────────────── */
(function () {
  const name = document.querySelector('.hero-name');
  if (!name) return;
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  function glitch() {
    name.classList.add('is-glitching');
    setTimeout(() => name.classList.remove('is-glitching'), 500);
    setTimeout(glitch, 4000 + Math.random() * 7000);
  }
  setTimeout(glitch, 3500);
})();

/* ── CV Download ─────────────────────────────────── */
document.querySelectorAll('[data-cv]').forEach(el => {
  const trigger = (e) => {
    e.preventDefault();
    const a = document.createElement('a');
    a.href     = atob(el.dataset.cv);
    a.download = '';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  };
  el.addEventListener('click', trigger);
  el.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ') trigger(e); });
});

/* ── Email Assembly ──────────────────────────────── */
document.querySelectorAll('[data-eu]').forEach(el => {
  const addr = el.dataset.eu + '@' + el.dataset.ed;
  el.href = 'mailto:' + addr;
  const val = el.querySelector('.contact-val');
  if (val) val.textContent = addr;
});

/* ── Typing Animation ────────────────────────────── */
const typedEl = document.getElementById('typed');
const phrases = window.SITE_PHRASES || [];

let pIdx = 0, cIdx = 0, deleting = false, timer;

function type() {
  const word = phrases[pIdx % phrases.length];
  if (!word) return;

  if (!deleting) {
    typedEl.textContent = word.slice(0, ++cIdx);
    if (cIdx === word.length) { deleting = true; timer = setTimeout(type, 2200); return; }
  } else {
    typedEl.textContent = word.slice(0, --cIdx);
    if (cIdx === 0) { deleting = false; pIdx++; timer = setTimeout(type, 350); return; }
  }
  timer = setTimeout(type, deleting ? 38 : 68);
}

function resetTyping() {
  clearTimeout(timer);
  pIdx = 0; cIdx = 0; deleting = false;
  typedEl.textContent = '';
  type();
}

resetTyping();

/* ── Scroll Reveal ───────────────────────────────── */
const revealObs = new IntersectionObserver((entries) => {
  entries.forEach((e, i) => {
    if (e.isIntersecting) {
      setTimeout(() => e.target.classList.add('visible'), i * 90);
      revealObs.unobserve(e.target);
    }
  });
}, { threshold: 0.1 });

document.querySelectorAll('.reveal').forEach(el => revealObs.observe(el));

/* ── Skill Bar Animation ─────────────────────────── */
const skillsObs = new IntersectionObserver((entries) => {
  entries.forEach(e => {
    if (e.isIntersecting) {
      e.target.querySelectorAll('.skill-fill').forEach((bar, i) =>
        setTimeout(() => bar.classList.add('go'), i * 110)
      );
      skillsObs.unobserve(e.target);
    }
  });
}, { threshold: 0.2 });

const sg = document.getElementById('skillsGrid');
if (sg) skillsObs.observe(sg);

/* ── Carousel ────────────────────────────────────── */
document.querySelectorAll('[data-carousel]').forEach(wrap => {
  const track    = wrap.querySelector('.is-carousel');
  const prevBtn  = wrap.querySelector('.carousel-btn--prev');
  const nextBtn  = wrap.querySelector('.carousel-btn--next');
  const dotsWrap = wrap.querySelector('.carousel-dots');
  if (!track) return;

  const cards = Array.from(track.children);

  // Scroll position of card i relative to the track's scrollable content
  function cardScrollLeft(i) {
    const trackRect = track.getBoundingClientRect();
    const cardRect  = cards[i].getBoundingClientRect();
    return track.scrollLeft + (cardRect.left - trackRect.left);
  }

  // Build dots
  const dots = cards.map((_, i) => {
    const dot = document.createElement('button');
    dot.className = 'carousel-dot';
    dot.setAttribute('aria-label', `${i + 1}`);
    dot.addEventListener('click', () => {
      track.scrollTo({ left: cardScrollLeft(i), behavior: 'smooth' });
    });
    dotsWrap.appendChild(dot);
    return dot;
  });

  function activeDot() {
    const trackLeft = track.getBoundingClientRect().left;
    let closest = 0, minDist = Infinity;
    cards.forEach((card, i) => {
      const dist = Math.abs(card.getBoundingClientRect().left - trackLeft);
      if (dist < minDist) { minDist = dist; closest = i; }
    });
    dots.forEach((d, i) => d.classList.toggle('active', i === closest));
  }

  function cardWidth() {
    const gap = parseFloat(getComputedStyle(track).columnGap) || 24;
    return cards[0].offsetWidth + gap;
  }

  prevBtn.addEventListener('click', () => track.scrollBy({ left: -cardWidth(), behavior: 'smooth' }));
  nextBtn.addEventListener('click', () => track.scrollBy({ left:  cardWidth(), behavior: 'smooth' }));

  track.addEventListener('scroll', activeDot, { passive: true });
  activeDot();
});

/* ── Contact Form ────────────────────────────────── */
(function () {
  const form = document.getElementById('contact-form');
  if (!form) return;

  // Stamp load time into hidden field — used by PHP timing check
  const timeField = document.getElementById('cf-time');
  if (timeField) timeField.value = Math.floor(Date.now() / 1000);

  const btn    = form.querySelector('.cf-submit');
  const status = form.querySelector('.cf-status');
  const i18n   = window.FORM_I18N || {};

  form.addEventListener('submit', async (e) => {
    e.preventDefault();

    // Basic client-side required check
    const required = form.querySelectorAll('[required]');
    let valid = true;
    required.forEach(el => {
      el.classList.toggle('cf-invalid', !el.value.trim());
      if (!el.value.trim()) valid = false;
    });
    if (!valid) {
      setStatus('err', i18n.error_fields);
      return;
    }

    btn.classList.add('loading');
    btn.disabled = true;
    setStatus('', '');

    try {
      const res  = await fetch('/api/contact.php', {
        method: 'POST',
        body:   new FormData(form),
      });
      const data = await res.json();

      if (data.success) {
        setStatus('ok', i18n.success);
        form.reset();
        // Re-stamp time after reset
        if (timeField) timeField.value = Math.floor(Date.now() / 1000);
      } else {
        setStatus('err', i18n.error);
      }
    } catch {
      setStatus('err', i18n.error);
    } finally {
      btn.classList.remove('loading');
      btn.disabled = false;
    }
  });

  // Clear invalid state on input
  form.querySelectorAll('input, textarea').forEach(el => {
    el.addEventListener('input', () => el.classList.remove('cf-invalid'));
  });

  // On reset: clear status message, invalid states, and re-stamp time
  form.addEventListener('reset', () => {
    setStatus('', '');
    form.querySelectorAll('.cf-invalid').forEach(el => el.classList.remove('cf-invalid'));
    if (timeField) setTimeout(() => { timeField.value = Math.floor(Date.now() / 1000); }, 0);
  });

  function setStatus(type, msg) {
    status.className = 'cf-status' + (type ? ' ' + type : '');
    status.textContent = msg;
  }
})();

/* ── Scroll Progress Bar ─────────────────────────── */
(function () {
  const bar = document.getElementById('scroll-progress');
  if (!bar) return;
  window.addEventListener('scroll', () => {
    const scrolled = document.documentElement.scrollTop;
    const total    = document.documentElement.scrollHeight - document.documentElement.clientHeight;
    const pct      = total > 0 ? (scrolled / total) * 100 : 0;
    bar.style.width = pct + '%';
    bar.setAttribute('aria-valuenow', Math.round(pct));
  }, { passive: true });
})();

/* ── Nav Border on Scroll ────────────────────────── */
const navEl   = document.getElementById('nav');
const isLight = () => document.documentElement.classList.contains('theme-light');
window.addEventListener('scroll', () => {
  navEl.style.borderBottomColor = scrollY > 60
    ? (isLight() ? 'rgba(168,189,216,0.9)' : 'rgba(24,40,64,0.9)')
    : (isLight() ? 'rgba(168,189,216,0.5)' : 'rgba(24,40,64,0.5)');
}, { passive: true });

/* ── Mobile Menu ─────────────────────────────────── */
const burger   = document.querySelector('.hamburger');
const navLinks = document.querySelector('.nav-links');
let menuOpen   = false;

function menuBg() {
  return isLight()
    ? { bg: 'rgba(240,244,248,0.97)', border: '1px solid rgba(168,189,216,0.8)' }
    : { bg: 'rgba(6,11,16,0.97)',     border: '1px solid rgba(24,40,64,0.9)'    };
}

function openMenu() {
  menuOpen = true;
  burger.setAttribute('aria-expanded', true);
  const { bg, border } = menuBg();
  Object.assign(navLinks.style, {
    display:       'flex',
    flexDirection: 'column',
    position:      'absolute',
    top:           '100%',
    left:          '0',
    right:         '0',
    background:    bg,
    padding:       '1rem 2rem',
    borderBottom:  border,
    gap:           '1rem'
  });
  navLinks.querySelector('.nav-theme-item').style.display = 'flex';
}

function closeMenu() {
  menuOpen = false;
  burger.setAttribute('aria-expanded', false);
  navLinks.style.display = 'none';
  navLinks.querySelector('.nav-theme-item').style.display = '';
}

burger.addEventListener('click', (e) => {
  e.stopPropagation();
  menuOpen ? closeMenu() : openMenu();
});

document.addEventListener('click', (e) => {
  if (menuOpen && !navEl.contains(e.target)) closeMenu();
});

document.addEventListener('touchstart', (e) => {
  if (menuOpen && !navEl.contains(e.target)) closeMenu();
}, { passive: true });

/* ── Theme Toggle ────────────────────────────────── */
(function () {
  const html     = document.documentElement;
  const toggles  = document.querySelectorAll('.theme-toggle');

  function currentTheme() {
    return html.classList.contains('theme-light') ? 'light' : 'dark';
  }

  function applyTheme(theme) {
    html.classList.remove('theme-light', 'theme-dark');
    html.classList.add('theme-' + theme);
    localStorage.setItem('theme', theme);
    updateIcons();
    // Refresh open mobile menu background
    if (menuOpen) {
      const { bg, border } = menuBg();
      navLinks.style.background   = bg;
      navLinks.style.borderBottom = border;
    }
  }

  function updateIcons() {
    const light = currentTheme() === 'light';
    toggles.forEach(btn => {
      btn.querySelector('i').className = light ? 'fa-solid fa-moon' : 'fa-solid fa-sun';
      const lbl = btn.querySelector('.theme-toggle-label');
      if (lbl) lbl.textContent = light ? 'Dark mode' : 'Light mode';
    });
  }

  toggles.forEach(btn => btn.addEventListener('click', () => {
    applyTheme(currentTheme() === 'light' ? 'dark' : 'light');
  }));

  updateIcons();
})();
