/*
  檔案功能：site.js
  被引用目的：為靜態 HTML 頁面加入互動層，讓導覽選單、動畫狀態與可及性屬性能依使用者操作而改變。
  編寫安排：等待 DOMContentLoaded 後才執行，確保 HTML 結構已載入；再使用 querySelector 取得元素，透過 classList 切換 CSS class，讓 JavaScript 控制狀態、CSS 負責視覺。
  與 HTML/CSS 的關係：HTML 提供 .site-header-toggle、.site-menu、.card、.widget 等 class；CSS 定義 .is-open、.js-reveal、.is-visible 的樣式；本檔負責在適當時機加入或移除這些 class。
*/

// 監聽事件；當指定事件發生時執行後方函式。
document.addEventListener("DOMContentLoaded", function () {
  // 宣告變數，保存 DOM 元素、狀態或資料。
  var menuButton = document.querySelector(".site-header-toggle");

  // 宣告變數，保存 DOM 元素、狀態或資料。
  var siteMenu = document.querySelector(".site-menu");

  // 條件判斷，只有符合條件時才執行內部程式。
  if (menuButton && siteMenu) {
    // 設定 HTML 屬性，常用於無障礙或互動狀態。
    menuButton.setAttribute("aria-label", "切換網站選單");

    // 設定 HTML 屬性，常用於無障礙或互動狀態。
    menuButton.setAttribute("aria-expanded", "false");

    // 監聽事件；當指定事件發生時執行後方函式。
    menuButton.addEventListener("click", function (event) {
      // 取消連結或按鈕的預設行為，改由 JavaScript 控制互動。
      event.preventDefault();

      // 宣告變數，保存 DOM 元素、狀態或資料。
      var isOpen = siteMenu.classList.toggle("is-open");

      // 設定 HTML 屬性，常用於無障礙或互動狀態。
      menuButton.setAttribute("aria-expanded", String(isOpen));
    });
  }

  // 宣告變數，保存 DOM 元素、狀態或資料。
  var revealItems = document.querySelectorAll(".card, .widget, .content, .sidebar");

  // 逐一處理一組元素或資料。
  revealItems.forEach(function (item) {
    // 新增 CSS class，讓元素套用指定樣式或動畫狀態。
    item.classList.add("js-reveal");
  });

  // 條件判斷，只有符合條件時才執行內部程式。
  if ("IntersectionObserver" in window) {
    // 宣告變數，保存 DOM 元素、狀態或資料。
    var observer = new IntersectionObserver(
      function (entries) {
        // 逐一處理一組元素或資料。
        entries.forEach(function (entry) {
          // 條件判斷，只有符合條件時才執行內部程式。
          if (entry.isIntersecting) {
            // 新增 CSS class，讓元素套用指定樣式或動畫狀態。
            entry.target.classList.add("is-visible");
            observer.unobserve(entry.target);
          }
        });
      },
      { threshold: 0.12 },
    );

    // 逐一處理一組元素或資料。
    revealItems.forEach(function (item) {
      observer.observe(item);
    });
  } else {
    // 逐一處理一組元素或資料。
    revealItems.forEach(function (item) {
      // 新增 CSS class，讓元素套用指定樣式或動畫狀態。
      item.classList.add("is-visible");
    });
  }
});


// 首頁 Canvas 互動背景：用淡淡的圓點、線條與透明度做出感測訊號 / 資料流的痕跡。
document.addEventListener("DOMContentLoaded", function () {
  var canvas = document.querySelector(".hero-canvas");
  var banner = document.querySelector(".site-banner");
  if (!canvas || !banner) return;

  var ctx = canvas.getContext("2d");
  var width = 0;
  var height = 0;
  var dpr = Math.min(window.devicePixelRatio || 1, 2);
  var particles = [];
  var pointer = { x: 0, y: 0, active: false };
  var lastMove = 0;

  function resizeCanvas() {
    var rect = banner.getBoundingClientRect();
    width = Math.max(1, rect.width);
    height = Math.max(1, rect.height);
    canvas.width = Math.floor(width * dpr);
    canvas.height = Math.floor(height * dpr);
    canvas.style.width = width + "px";
    canvas.style.height = height + "px";
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
  }

  function addParticle(x, y, strong) {
    particles.push({
      x: x,
      y: y,
      vx: (Math.random() - 0.5) * (strong ? 1.2 : 0.45),
      vy: (Math.random() - 0.5) * (strong ? 1.2 : 0.45),
      r: strong ? 2 + Math.random() * 5 : 1 + Math.random() * 3,
      life: 1,
      decay: strong ? 0.012 : 0.008,
      hue: Math.random() > 0.5 ? 195 : 260
    });
    if (particles.length > 90) particles.splice(0, particles.length - 90);
  }

  function seedParticles() {
    particles = [];
    for (var i = 0; i < 36; i++) {
      addParticle(Math.random() * width, Math.random() * height, false);
    }
  }

  function onMove(event) {
    var rect = banner.getBoundingClientRect();
    pointer.x = event.clientX - rect.left;
    pointer.y = event.clientY - rect.top;
    pointer.active = true;

    var now = Date.now();
    if (now - lastMove > 45) {
      addParticle(pointer.x, pointer.y, true);
      lastMove = now;
    }
  }

  function draw() {
    ctx.clearRect(0, 0, width, height);

    // 淡淡的掃描線，讓背景像是感測資料流。
    ctx.save();
    ctx.globalAlpha = 0.08;
    ctx.strokeStyle = "rgba(255,255,255,0.32)";
    ctx.lineWidth = 1;
    for (var y = 24; y < height; y += 44) {
      ctx.beginPath();
      ctx.moveTo(0, y);
      ctx.lineTo(width, y + Math.sin(Date.now() * 0.001 + y) * 8);
      ctx.stroke();
    }
    ctx.restore();

    for (var i = particles.length - 1; i >= 0; i--) {
      var p = particles[i];
      p.x += p.vx;
      p.y += p.vy;
      p.life -= p.decay;
      p.r += 0.025;

      if (pointer.active) {
        var dx = pointer.x - p.x;
        var dy = pointer.y - p.y;
        var dist = Math.sqrt(dx * dx + dy * dy) || 1;
        if (dist < 180) {
          p.vx += (dx / dist) * 0.006;
          p.vy += (dy / dist) * 0.006;
        }
      }

      if (p.life <= 0 || p.x < -40 || p.x > width + 40 || p.y < -40 || p.y > height + 40) {
        particles.splice(i, 1);
        continue;
      }

      ctx.save();
      ctx.globalAlpha = Math.max(0, p.life) * 0.35;
      ctx.strokeStyle = "hsla(" + p.hue + ", 80%, 78%, 0.75)";
      ctx.fillStyle = "hsla(" + p.hue + ", 80%, 78%, 0.32)";
      ctx.lineWidth = 1;
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.r * 4.2, 0, Math.PI * 2);
      ctx.stroke();
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
      ctx.fill();
      ctx.restore();
    }

    // 距離很近的點用細線連起來，像資料節點。
    ctx.save();
    ctx.lineWidth = 1;
    for (var a = 0; a < particles.length; a++) {
      for (var b = a + 1; b < particles.length; b++) {
        var pa = particles[a];
        var pb = particles[b];
        var lx = pa.x - pb.x;
        var ly = pa.y - pb.y;
        var ld = Math.sqrt(lx * lx + ly * ly);
        if (ld < 120) {
          ctx.globalAlpha = (1 - ld / 120) * 0.12 * Math.min(pa.life, pb.life);
          ctx.strokeStyle = "rgba(255,255,255,0.9)";
          ctx.beginPath();
          ctx.moveTo(pa.x, pa.y);
          ctx.lineTo(pb.x, pb.y);
          ctx.stroke();
        }
      }
    }
    ctx.restore();

    if (particles.length < 48 && Math.random() < 0.08) {
      addParticle(Math.random() * width, Math.random() * height, false);
    }

    window.requestAnimationFrame(draw);
  }

  resizeCanvas();
  seedParticles();
  draw();

  window.addEventListener("resize", function () {
    resizeCanvas();
    seedParticles();
  });
  banner.addEventListener("mousemove", onMove);
  banner.addEventListener("touchmove", function (event) {
    if (!event.touches || !event.touches.length) return;
    var touch = event.touches[0];
    onMove({ clientX: touch.clientX, clientY: touch.clientY });
  }, { passive: true });
  banner.addEventListener("mouseleave", function () {
    pointer.active = false;
  });
});

// 全站 Canvas 互動背景：淡淡的滑鼠殘影、漂浮粒子與資料流線條。
// 只作為氣氛層，不參與版面排版，所以不會改動原本內容。
document.addEventListener("DOMContentLoaded", function () {
  if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

  var canvas = document.createElement("canvas");
  canvas.className = "site-atmosphere-canvas";
  canvas.setAttribute("aria-hidden", "true");
  document.body.appendChild(canvas);

  var ctx = canvas.getContext("2d");
  var dpr = Math.min(window.devicePixelRatio || 1, 2);
  var w = 0;
  var h = 0;
  var mouse = { x: -9999, y: -9999, active: false };
  var particles = [];
  var traces = [];
  var lastMove = 0;

  function resize() {
    w = window.innerWidth;
    h = window.innerHeight;
    canvas.width = Math.floor(w * dpr);
    canvas.height = Math.floor(h * dpr);
    canvas.style.width = w + "px";
    canvas.style.height = h + "px";
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

    var target = Math.min(70, Math.max(36, Math.floor(w * h / 26000)));
    particles = [];
    for (var i = 0; i < target; i++) {
      particles.push({
        x: Math.random() * w,
        y: Math.random() * h,
        vx: (Math.random() - 0.5) * 0.25,
        vy: (Math.random() - 0.5) * 0.25,
        r: 0.6 + Math.random() * 1.8,
        a: 0.12 + Math.random() * 0.25
      });
    }
  }

  function addTrace(x, y) {
    traces.push({
      x: x,
      y: y,
      r: 4 + Math.random() * 12,
      life: 1,
      vx: (Math.random() - 0.5) * 0.7,
      vy: (Math.random() - 0.5) * 0.7
    });
    if (traces.length > 70) traces.shift();
  }

  window.addEventListener("mousemove", function (event) {
    mouse.x = event.clientX;
    mouse.y = event.clientY;
    mouse.active = true;
    var now = Date.now();
    if (now - lastMove > 28) {
      addTrace(mouse.x, mouse.y);
      lastMove = now;
    }
  });

  window.addEventListener("touchmove", function (event) {
    if (!event.touches || !event.touches.length) return;
    mouse.x = event.touches[0].clientX;
    mouse.y = event.touches[0].clientY;
    mouse.active = true;
    addTrace(mouse.x, mouse.y);
  }, { passive: true });

  window.addEventListener("mouseleave", function () {
    mouse.active = false;
  });

  function draw() {
    ctx.clearRect(0, 0, w, h);

    // 微弱的底層霧感
    var g = ctx.createRadialGradient(w * 0.55, h * 0.45, 40, w * 0.55, h * 0.45, Math.max(w, h) * 0.7);
    g.addColorStop(0, "rgba(190,210,220,0.045)");
    g.addColorStop(1, "rgba(0,0,0,0)");
    ctx.fillStyle = g;
    ctx.fillRect(0, 0, w, h);

    // 漂浮粒子
    for (var i = 0; i < particles.length; i++) {
      var p = particles[i];
      if (mouse.active) {
        var dx = mouse.x - p.x;
        var dy = mouse.y - p.y;
        var dist = Math.sqrt(dx * dx + dy * dy) || 1;
        if (dist < 160) {
          p.vx -= (dx / dist) * 0.006;
          p.vy -= (dy / dist) * 0.006;
        }
      }
      p.x += p.vx;
      p.y += p.vy;
      p.vx *= 0.992;
      p.vy *= 0.992;
      if (p.x < -20) p.x = w + 20;
      if (p.x > w + 20) p.x = -20;
      if (p.y < -20) p.y = h + 20;
      if (p.y > h + 20) p.y = -20;

      ctx.beginPath();
      ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
      ctx.fillStyle = "rgba(235,242,245," + p.a + ")";
      ctx.fill();
    }

    // 粒子之間的細線資料流
    for (var a = 0; a < particles.length; a++) {
      for (var b = a + 1; b < particles.length; b++) {
        var p1 = particles[a];
        var p2 = particles[b];
        var x = p1.x - p2.x;
        var y = p1.y - p2.y;
        var d = Math.sqrt(x * x + y * y);
        if (d < 105) {
          ctx.beginPath();
          ctx.moveTo(p1.x, p1.y);
          ctx.lineTo(p2.x, p2.y);
          ctx.strokeStyle = "rgba(210,225,230," + (0.055 * (1 - d / 105)) + ")";
          ctx.lineWidth = 0.7;
          ctx.stroke();
        }
      }
    }

    // 滑鼠 / 手指殘影，像感測痕跡
    for (var t = traces.length - 1; t >= 0; t--) {
      var tr = traces[t];
      tr.x += tr.vx;
      tr.y += tr.vy;
      tr.r += 0.55;
      tr.life -= 0.018;
      if (tr.life <= 0) {
        traces.splice(t, 1);
        continue;
      }
      ctx.beginPath();
      ctx.arc(tr.x, tr.y, tr.r, 0, Math.PI * 2);
      ctx.strokeStyle = "rgba(255,255,255," + (0.30 * tr.life) + ")";
      ctx.lineWidth = 1;
      ctx.stroke();
      ctx.beginPath();
      ctx.arc(tr.x, tr.y, Math.max(1, tr.r * 0.16), 0, Math.PI * 2);
      ctx.fillStyle = "rgba(255,255,255," + (0.24 * tr.life) + ")";
      ctx.fill();
    }

    requestAnimationFrame(draw);
  }

  resize();
  window.addEventListener("resize", resize);
  draw();
});



// 全站滑鼠感測補強：在每一頁都產生可見但不擋字的透明光暈。
document.addEventListener("DOMContentLoaded", function () {
  if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
  var last = 0;
  function addCursorAura(x, y) {
    var aura = document.createElement("span");
    aura.className = "cursor-aura";
    aura.style.left = x + "px";
    aura.style.top = y + "px";
    document.body.appendChild(aura);
    window.setTimeout(function () { aura.remove(); }, 900);
  }
  window.addEventListener("mousemove", function (event) {
    var now = Date.now();
    if (now - last > 70) {
      addCursorAura(event.clientX, event.clientY);
      last = now;
    }
  });
  window.addEventListener("touchmove", function (event) {
    if (!event.touches || !event.touches.length) return;
    var t = event.touches[0];
    addCursorAura(t.clientX, t.clientY);
  }, { passive: true });
});

// 作品卡點擊 / hover 訊號：讓可點進去的卡片有放大、光圈與轉場感。
document.addEventListener("DOMContentLoaded", function () {
  var cards = document.querySelectorAll(".work-link, .portfolio-card");
  var prefersReduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  function setPointerVars(card, event) {
    var rect = card.getBoundingClientRect();
    var x = ((event.clientX - rect.left) / rect.width) * 100;
    var y = ((event.clientY - rect.top) / rect.height) * 100;
    card.style.setProperty("--pointer-x", x + "%");
    card.style.setProperty("--pointer-y", y + "%");
  }

  function addPageSignal(x, y) {
    var signal = document.createElement("span");
    signal.className = "page-click-signal";
    signal.style.setProperty("--x", x + "px");
    signal.style.setProperty("--y", y + "px");
    document.body.appendChild(signal);
    window.setTimeout(function () { signal.remove(); }, 850);
  }

  cards.forEach(function (card) {
    card.addEventListener("pointermove", function (event) {
      setPointerVars(card, event);
    });

    card.addEventListener("click", function (event) {
      if (prefersReduced) return;
      if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || card.target === "_blank") return;

      var href = card.getAttribute("href");
      if (!href || href.charAt(0) === "#") return;

      event.preventDefault();
      setPointerVars(card, event);
      card.classList.add("is-clicking");
      document.body.classList.add("is-leaving");

      var rect = card.getBoundingClientRect();
      var pulse = document.createElement("span");
      pulse.className = "card-pulse";
      pulse.style.setProperty("--pulse-x", (event.clientX - rect.left) + "px");
      pulse.style.setProperty("--pulse-y", (event.clientY - rect.top) + "px");
      card.appendChild(pulse);
      addPageSignal(event.clientX, event.clientY);

      window.setTimeout(function () {
        window.location.href = href;
      }, 260);
    });
  });

  // 所有頁面都保留點擊訊號，作品詳情頁點擊返回 / 聯絡也會有反應。
  document.addEventListener("click", function (event) {
    if (prefersReduced) return;
    if (event.target.closest(".work-link, .portfolio-card")) return;
    if (event.target.closest("a, button, input[type='submit']")) {
      addPageSignal(event.clientX, event.clientY);
    }
  });
});
