/*
 * Copyright © 2026 Em Zakharov
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

document.addEventListener("DOMContentLoaded", (_) => {
  const playbackToggle      = document.getElementsByName("playback-toggle-switch")[0];
  const recordToggle        = document.getElementsByName("record-toggle-switch")[0];
  const clickableListItems  = document.querySelectorAll("#how > ul > li > ul > li");
  

  // Toggle switches ===
  // ===================
  let debouncing = false;
  function setDebounceTimeout() { setTimeout(() => { debouncing = false }, 200) }
      // 200 ms, because slow enough to absorb event delays (problems noticed at 100 ms),
      // but fast enough to be unnoticeable (~ human reaction time).
  function toggleSwitch(e) {
    if (debouncing) { return }

    operateToggleSwitch(e, "flip", false);
  }
  playbackToggle.onclick = toggleSwitch;
  recordToggle.onclick   = toggleSwitch;

  // To allow swiping the toggle switches up/down on touch devices
  let toggleTouchStartY = 0;
  let toggleTouchEndY   = 0;
  function handleTouchStart(e) { toggleTouchStartY = e.changedTouches[0].screenY; }
  function handleTouchEnd(e) {
    toggleTouchEndY = e.changedTouches[0].screenY;

    const direction = checkDirection(toggleTouchStartY, toggleTouchEndY);
    // If the user's intention is to swipe the switch (`direction` is not "none"), it can happen
    // that the switch is also considered `click`ed. This causes a double flip of the switch: one
    // from the user's intetion, then reversal by the `click` event's "flip". To prevent that
    // reversing "flip", when a valid swipe is registered, we enter a `debouncing` state. During
    // this state, any `click` events on the switch are ignored. Hence, double flips are avoided.
    // The `debouncing` state is left after a timeout to allow intentional `click` events to be
    // correctly handled again.
    if (direction === "up" || direction === "down") {
      debouncing = true;
      setDebounceTimeout()
    }
    operateToggleSwitch(e, direction, false);
  }
  playbackToggle.ontouchstart = handleTouchStart;
  playbackToggle.ontouchend   = handleTouchEnd;
  recordToggle.ontouchstart   = handleTouchStart;
  recordToggle.ontouchend     = handleTouchEnd;

  loadToggleStates([playbackToggle, recordToggle]);

  // Prevent scrolling while swiping the switch
  document.querySelector(".record.toggle").addEventListener("touchmove", (e) => { e.preventDefault() }, { passive: false });
  document.querySelector(".playback.toggle").addEventListener("touchmove", (e) => { e.preventDefault() }, { passive: false });

  clickableListItems.forEach((item) => {
    item.onclick = (e) => {
      const toggleElement = item.id.startsWith("record") ? recordToggle : playbackToggle;
      
      if (item.classList.contains("faded")) {
        operateToggleSwitch(toggleElement, "flip", false);
      }
    };
  });
  // ===================

  document.onkeydown = (e) => {
    if (e.repeat) { return }
    if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return }

    if (document.activeElement === document.getElementById("dmt-label")
        && (e.key === " " || e.key === "Enter")) {
      document.activeElement.click();
      if (e.key === " ") { e.preventDefault(); } // Prevent scroll
    }
  };

  // Keyboard shortcuts control ===
  // ==============================
  const recordShortcutEnabled   = document.getElementById("record-shortcut-enabled");
  const recordShortcutKey       = document.getElementById("record-shortcut-key");
  const playbackShortcutEnabled = document.getElementById("playback-shortcut-enabled");
  const playbackShortcutKey     = document.getElementById("playback-shortcut-key");

  recordShortcutEnabled.onchange = () => {
    if (recordShortcutEnabled.checked) { localStorage.setItem("parrot.recordShortcutEnabled", "true"); }
    else { localStorage.setItem("parrot.recordShortcutEnabled", "false"); }
  };
  playbackShortcutEnabled.onchange = () => {
    if (playbackShortcutEnabled.checked) { localStorage.setItem("parrot.playbackShortcutEnabled", "true"); }
    else { localStorage.setItem("parrot.playbackShortcutEnabled", "false"); }
  };

  recordShortcutKey.onchange = (e) => { localStorage.setItem("parrot.recordShortcutKey", e.target.value); };
  playbackShortcutKey.onchange = (e) => { localStorage.setItem("parrot.playbackShortcutKey", e.target.value); };

  const recordShortcutEnabledPreference = localStorage.getItem("parrot.recordShortcutEnabled");
  if (recordShortcutEnabledPreference) { recordShortcutEnabledPreference === "true" ? recordShortcutEnabled.checked = true : recordShortcutEnabled.checked = false; }

  const recordShortcutKeyPreference = localStorage.getItem("parrot.recordShortcutKey");
  if (recordShortcutKeyPreference) { recordShortcutKey.value = recordShortcutKeyPreference; }

  const playbackShortcutEnabledPreference = localStorage.getItem("parrot.playbackShortcutEnabled");
  if (playbackShortcutEnabledPreference) { playbackShortcutEnabledPreference === "true" ? playbackShortcutEnabled.checked = true : playbackShortcutEnabled.checked = false; }

  const playbackShortcutKeyPreference = localStorage.getItem("parrot.playbackShortcutKey");
  if (playbackShortcutKeyPreference) { playbackShortcutKey.value = playbackShortcutKeyPreference; }
  // ==============================
});

// =================================================================================================

function checkDirection(touchstartY, touchendY) {
  // Smallest change to consider `touchendY` != `touchstartY` is about 20px (on iPhone)
  if (touchendY < touchstartY) { return "up" }
  if (touchendY > touchstartY) { return "down" }
  // When `touchendY` == `touchstartY` (below the "swiped" threshold), the toggle switch `<button>`
  // is also considered `click`ed. To prevent a double flip of the switch (one from the
  // not-big-enough "swipe" and the other from the `click`), return a "none" to prevent triggering
  // a `toggleUp()` or `toggleDown()` from the not-big-enough "swipe" in `operateToggleSwitch(...)`.
  return "none";
}

function operateToggleSwitch(e, direction, quiet) {
  // Bubble up to the parent <div .toggle>
  let target = e instanceof Event ? e.target : e; // otherwise directly an HTMLElement
  while (target.localName != "button") {
    target = target.parentElement;
  }
  const toggleRoot = target.parentElement;

  let toggleType = null;
  if (toggleRoot.classList.contains("playback")) {
    toggleType = "playback";
  } else {
    toggleType = "record";
  }

  const pressCheckbox = toggleRoot.querySelector(`input[name="${toggleType}-toggle-press"]`);
  const holdCheckbox  = toggleRoot.querySelector(`input[name="${toggleType}-toggle-hold"]`);

  const currentState = pressCheckbox.checked && !holdCheckbox.checked ? "up" : "down";

  if ((direction === "up"   || direction === "flip") && currentState === "down") {
    toggleUp();
    pressCheckbox.checked = true;
    holdCheckbox.checked  = false;
  }
  if ((direction === "down" || direction === "flip") && currentState === "up") {
    toggleDown();
    pressCheckbox.checked = false;
    holdCheckbox.checked  = true;
  }

  async function toggleUp() {
    if (!quiet) {
      try {
        await document.getElementById("switch-up").play()
      } catch (ex) {
        if (ex.name === "NotAllowedError") {
          console.log("Toggle up: not allowed to play sound until the toggle has been clicked first.")
        }
      }
    }

    const ariaLabelText = `Toggle switch for ${toggleType} button mode. Currently in press to start/stop mode. Activate to switch to hold to ${toggleType} mode.`;

    const toggleButton  = toggleRoot.querySelector("button");
    toggleButton.classList.remove("down");
    toggleButton.classList.add("up");
    toggleButton.setAttribute("aria-label", ariaLabelText);

    const toggleShaftImage = toggleRoot.querySelector("img");
    toggleShaftImage.classList.remove("shaft-down");
    toggleShaftImage.classList.add("shaft-up");
    toggleShaftImage.src = "toggle-shaft-up.webp";

    const toggleSleeveShadow = toggleRoot.querySelector("div.sleeveshadow-down");
    toggleSleeveShadow.classList.remove("sleeveshadow-down");
    toggleSleeveShadow.classList.add("sleeveshadow-up");

    document.getElementById(`${toggleType}-start-stop`).classList.remove("faded");
    document.getElementById(`${toggleType}-hold`).classList.add("faded");

    localStorage.setItem(`parrot.${toggleType}Toggle`, "up");
  }

  async function toggleDown() {
    if (!quiet) {
      try {
        await document.getElementById("switch-down").play()
      } catch (ex) {
        if (ex.name === "NotAllowedError") {
          console.log("Toggle down: not allowed to play sound until the toggle has been clicked first.")
        }
      }
    }

    const ariaLabelText = `Toggle switch for ${toggleType} button mode. Currently in hold to ${toggleType} mode. Activate to switch to press to start/stop mode.`;

    const toggleButton  = toggleRoot.querySelector("button");
    toggleButton.classList.remove("up");
    toggleButton.classList.add("down");
    toggleButton.setAttribute("aria-label", ariaLabelText);

    const toggleShaftImage = toggleRoot.querySelector("img");
    toggleShaftImage.classList.remove("shaft-up");
    toggleShaftImage.classList.add("shaft-down");
    toggleShaftImage.src = "toggle-shaft-down.webp";

    const toggleSleeveShadow = toggleRoot.querySelector("div.sleeveshadow-up");
    toggleSleeveShadow.classList.remove("sleeveshadow-up");
    toggleSleeveShadow.classList.add("sleeveshadow-down");

    document.getElementById(`${toggleType}-hold`).classList.remove("faded");
    document.getElementById(`${toggleType}-start-stop`).classList.add("faded");

    localStorage.setItem(`parrot.${toggleType}Toggle`, "down");
  }
}

function loadToggleStates(htmlElements) {
  ["playback", "record"].forEach((value, i) => {
    const pressCheckbox =
      htmlElements[i].parentElement.querySelector(`input[name="${value}-toggle-press"]`);
    const holdCheckbox  =
      htmlElements[i].parentElement.querySelector(`input[name="${value}-toggle-hold"]`);

    const currentState = pressCheckbox.checked && !holdCheckbox.checked ? "up" : "down";
    const toggleStatePreference = localStorage.getItem(`parrot.${value}Toggle`);
    if (toggleStatePreference && toggleStatePreference !== currentState) {
      operateToggleSwitch(htmlElements[i], "flip", true);
    }
  })
}
