/* Focumi - Versi Spektakuler — FIXED + FEATURES
   Perubahan utama:
   - Planner diganti Mini Calendar (event create/save/delete)
   - Menjaga fitur lain (todos, notes, pomodoro, mood, ambience, music)
   - FIXES:
     * notes could not be edited because drag start prevented focus — avoid starting drag when clicking inside .note-text
     * wheel: previously empty div, now a canvas is rendered and drawn with segments based on todos.
*/

/* ---------- Cookies helpers (unchanged) ---------- */
function setCookie(name, value, days = 365) {
  const d = new Date();
  d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
  document.cookie =
    name +
    "=" +
    encodeURIComponent(JSON.stringify(value)) +
    ";expires=" +
    d.toUTCString() +
    ";path=/";
}
function getCookie(name) {
  const v = document.cookie.split("; ").find((row) => row.startsWith(name + "="));
  if (!v) return null;
  try {
    return JSON.parse(decodeURIComponent(v.split("=")[1]));
  } catch (e) {
    return null;
  }
}

/* ---------- Feature toggles + visibility memory ---------- */
function applyVisibilityMap(map) {
  if (!map) return;
  Object.keys(map).forEach((id) => {
    const show = !!map[id];
    const $w = $("#" + id);
    if (!$w.length) return;
    if (show) $w.show();
    else $w.hide();
    $('.feature-btn[data-target="' + id + '"]').toggleClass("active", show);
  });
}

$(document).on("click", ".feature-btn", function () {
  const targetId = $(this).data("target");
  const $targetWidget = $("#" + targetId);
  $targetWidget.fadeToggle();
  $(this).toggleClass("active");
  // save visibility
  const visibility = getCookie("focumi_visibility") || {};
  visibility[targetId] = $targetWidget.is(":visible");
  setCookie("focumi_visibility", visibility);
});

// open defaults first visit
if (!getCookie("focumi_visited_before")) {
  const defaults = { todo: true, pomodoro: true, calendar: true };
  applyVisibilityMap(defaults);
  setCookie("focumi_visibility", defaults);
  setCookie("focumi_visited_before", true);
}

/* ---------- LAYOUT ORDER (drag/drop to reorder widgets) ---------- */
function saveLayoutOrder() {
  const order = $("#workspace")
    .children(".widget")
    .map(function () {
      return this.id;
    })
    .get();
  setCookie("focumi_layout_order", order);
}
function applyLayoutOrder() {
  const order = getCookie("focumi_layout_order");
  if (!order || !Array.isArray(order)) return;
  const $ws = $("#workspace");
  order.forEach((id) => {
    const $el = $("#" + id);
    if ($el.length) $ws.append($el);
  });
}

// make all widgets draggable attribute present (for HTML5 dragstart)
$(".widget").attr("draggable", "true");

// drag workspace widgets (fixed handlers)
$(document).on("dragstart", ".widget", function (e) {
  const dt = e.originalEvent.dataTransfer;
  dt.setData("text/widget-id", this.id || "");
});
$(document).on("dragover", "#workspace .widget", function (e) {
  e.preventDefault();
});
$(document).on("drop", "#workspace .widget", function (e) {
  e.preventDefault();
  const draggedId = e.originalEvent.dataTransfer.getData("text/widget-id");
  const $target = $(this);
  if (!draggedId) return;
  const $dragged = $("#" + draggedId);
  if (!$dragged.length || !$target.length) return;
  $dragged.insertBefore($target);
  saveLayoutOrder();
});

$(document).ready(function () {
  applyLayoutOrder();
  applyVisibilityMap(getCookie("focumi_visibility"));
});

/* ---------- THEME picker (fixed) ---------- */
$("#themePicker").on("change", function () {
  const t = $(this).val();
  document.body.classList.remove("theme-pastel", "theme-matrix", "theme-glass");
  if (t === "matrix") document.body.classList.add("theme-matrix");
  else if (t === "glass") document.body.classList.add("theme-glass");
  else if (t === "minimal") {
    /* no class */
  } else document.body.classList.add("theme-pastel");
  setCookie("focumi_theme", t);

  // Update pomodoro chart color to match current theme accent variable
  try {
    const accent =
      getComputedStyle(document.documentElement).getPropertyValue("--accent").trim() ||
      "#7c3aed";
    if (window.pomoChart) {
      window.pomoChart.data.datasets[0].backgroundColor = [accent];
      window.pomoChart.update();
    }
  } catch (e) {
    // non-critical: leave chart as-is if update fails
  }
});
const savedTheme = getCookie("focumi_theme");
if (savedTheme) $("#themePicker").val(savedTheme).trigger("change");

/* ---------- TODO list ---------- */
let todos = getCookie("focumi_todos") || [];
function renderTodos() {
  $("#todoList").empty();
  if (!todos.length)
    $("#todoList").append('<div class="text-muted">Belum ada tugas</div>');

  todos.forEach((t, i) => {
    const el = $(
      `<div class='d-flex justify-content-between align-items-center p-2 mb-2 rounded todo-item'
         style='background:linear-gradient(90deg,#fff,#f7f9ff);position:relative'></div>`
    );
    const left = $("<div class='d-flex align-items-center gap-2'></div>");
    const chk = $('<input type="checkbox" class="todo-chk">')
      .prop("checked", !!t.done)
      .on("change", function () {
        toggleTodoDone(i);
      });
    const txt = $('<div class="fw-semibold todo-text"></div>').text(t.text);
    if (t.done) txt.css({ "text-decoration": "line-through", opacity: 0.6 });
    left.append(chk, $("<div>").append(txt).append(`<div class="text-muted small">${t.cat}</div>`));

    const right = $("<div></div>");
    const delBtn = $('<button class="btn btn-sm btn-danger">✕</button>').on(
      "click",
      () => {
        delTodo(i);
      }
    );
    right.append(delBtn);

    el.append(left, right);
    $("#todoList").append(el);
  });

  // ensure wheel redraw to reflect current tasks
  renderWheel();
}
function saveTodos() {
  setCookie("focumi_todos", todos);
}
window.delTodo = function (i) {
  todos.splice(i, 1);
  saveTodos();
  renderTodos();
  updateDashboard();
};
window.toggleTodoDone = function (i) {
  todos[i].done = !todos[i].done;
  saveTodos();
  renderTodos();
  updateDashboard();
};
$("#addTodo").on("click", function () {
  const text = $("#todoText").val().trim();
  const cat = $("#todoCat").val();
  if (!text) return;
  todos.push({ text, cat, done: false, created: Date.now() });
  saveTodos();
  renderTodos();
  $("#todoText").val("");
  updateDashboard();
});
renderTodos();

/* ---------- Pomodoro (templates, no sessions array) ---------- */
let pomo =
  getCookie("focumi_pomo") || {
    mode: 25, // minutes
    break: 5,
    remaining: 25 * 60,
    running: false,
    completedCycles: 0,
    selectedTemplate: "25/5",
  };
let pomoInterval = null;
function updatePomoDisplay() {
  const m = Math.floor(pomo.remaining / 60),
    s = pomo.remaining % 60;
  $("#pomoDisplay").text(
    String(m).padStart(2, "0") + ":" + String(s).padStart(2, "0")
  );
}
updatePomoDisplay();

function startPomo() {
  if (pomo.running) return;
  pomo.running = true;
  setCookie("focumi_pomo", pomo);
  pomoInterval = setInterval(() => {
    if (pomo.remaining <= 0) {
      clearInterval(pomoInterval);
      pomo.running = false;
      pomo.completedCycles = (pomo.completedCycles || 0) + 1;
      // play alert sound when pomodoro completes
      try {
        if (window.alertAudio) {
          window.alertAudio.currentTime = 0;
          window.alertAudio.play().catch(() => {});
        }
      } catch (e) {
        // ignore play errors
      }
      // reset to break if template says
      notify("Sesi selesai — istirahat!");
      // set break countdown
      pomo.remaining = (pomo.break || 5) * 60;
      setCookie("focumi_pomo", pomo);
      renderPomoStats();
      updateDashboard();
      return;
    }
    pomo.remaining--;
    updatePomoDisplay();
  }, 1000);
}
function pausePomo() {
  pomo.running = false;
  clearInterval(pomoInterval);
  setCookie("focumi_pomo", pomo);
}
function resetPomo() {
  pausePomo();

  // STOP alert audio (if it's currently playing from previous pomodoro completion)
  try {
    if (window.alertAudio && !window.alertAudio.paused) {
      window.alertAudio.pause();
      window.alertAudio.currentTime = 0;
    } else if (window.alertAudio) {
      // even if paused, reset position to ensure it's not left mid-way
      window.alertAudio.currentTime = 0;
    }
  } catch (e) {
    // non-critical: ignore audio stop errors
  }

  pomo.remaining = (pomo.mode || 25) * 60;
  setCookie("focumi_pomo", pomo);
  updatePomoDisplay();
}
$("#pomoStart").on("click", startPomo);
$("#pomoPause").on("click", pausePomo);
$("#pomoReset").on("click", resetPomo);

/* Template selection */
$(document).on("click", ".pomo-template", function () {
  $(".pomo-template").removeClass("active");
  $(this).addClass("active");
  const m = parseInt($(this).data("min"), 10);
  const b = parseInt($(this).data("break"), 10);
  pomo.mode = m;
  pomo.break = b;
  pomo.remaining = m * 60;
  pomo.selectedTemplate = m + "/" + b;
  setCookie("focumi_pomo", pomo);
  $("#pomoNote").text("Template: " + pomo.selectedTemplate + " (focus / break)");
  updatePomoDisplay();
});

/* Custom template (IN-LINE, no prompt) */
$("#pomoCustomApply").on("click", function () {
  const m = parseInt($("#pomoCustomFocus").val(), 10);
  const b = parseInt($("#pomoCustomBreak").val(), 10);
  if (isNaN(m) || isNaN(b) || m <= 0 || b < 0) {
    alert("Masukkan angka valid untuk fokus dan istirahat");
    return;
  }
  pomo.mode = m;
  pomo.break = b;
  pomo.remaining = m * 60;
  pomo.selectedTemplate = m + "/" + b;
  setCookie("focumi_pomo", pomo);
  $("#pomoNote").text("Template: " + pomo.selectedTemplate + " (custom)");
  updatePomoDisplay();

  // ensure template buttons lose 'active'
  $(".pomo-template").removeClass("active");
});

/* allow pressing Enter inside custom inputs to apply */
$(document).on("keypress", "#pomoCustomFocus, #pomoCustomBreak", function (e) {
  if (e.key === "Enter") {
    e.preventDefault();
    $("#pomoCustomApply").trigger("click");
  }
});

/* Initialize the custom input values from saved pomo */
$(document).ready(function () {
  $("#pomoCustomFocus").val(pomo.mode || 25);
  $("#pomoCustomBreak").val(pomo.break || 5);
});

/* Pomodoro stats chart */
const ctxP =
  document.getElementById("pomoStats") &&
  document.getElementById("pomoStats").getContext("2d");
let pomoChart = null;
if (ctxP) {
  // compute current accent color from CSS variables so Chart uses the actual color
  const accent =
    (getComputedStyle(document.documentElement).getPropertyValue("--accent") || "").trim() ||
    "#7c3aed";

  pomoChart = new Chart(ctxP, {
    type: "doughnut",
    data: {
      labels: ["Completed"],
      datasets: [{ data: [pomo.completedCycles || 0], backgroundColor: [accent] }],
    },
  });

  // expose globally so theme change handler can update it
  window.pomoChart = pomoChart;

  function renderPomoStats() {
    const s = pomo.completedCycles || 0;
    pomoChart.data.datasets[0].data = [s];
    pomoChart.update();
  }
  renderPomoStats();
}

/* ---------- Quotes (now as toast on refresh + manual) ---------- */
const quotes = [
  "everything will be okay at the end :3",
  "love yourself first, and everyone will love you always!",
  "may you always bloom at the right time and place.",
  "failure isn't opposite of success, it's part of success.",
  "be yourself, and never to surrender.",
  "you deserve all the good things in your life <3",
  "keep going and keep growing.",
  "keep moving forward! ><",
  "you are smarter than you think!",
  "don't wish for it, work for it.",
  "never lose your hope, make it happen into your life."
];
function typeQuote(q) {
  const box = $("#quoteBox");
  box.text(q);
}

/* ---------- Quote modal (centered originally, now shown top-center via CSS) ---------- */
/* showQuoteModal: displays a centered quote modal with optional auto-hide */
function showQuoteModal(q, opts = {}) {
  const timeout = opts.timeout || 3600;
  const $modal = $("#quoteModal");
  const $text = $("#quoteText");
  if (!$modal.length || !$text.length) return;
  $text.text(q);
  // ensure hidden overlay is made visible; CSS positions it at top-center (styles.css)
  $modal.stop(true, true).fadeIn(180);
  // auto-hide after timeout (if timeout > 0)
  if (timeout > 0) {
    clearTimeout($modal.data("hideTimer"));
    const t = setTimeout(() => {
      $modal.fadeOut(240);
    }, timeout);
    $modal.data("hideTimer", t);
  }
}
$("#closeQuote").on("click", function () {
  $("#quoteModal").fadeOut(180);
});

/* ---------- Music player (existing ambient tracks + mood-backed tracks) ---------- */
const audio = new Audio();
audio.loop = true;
audio.volume = 0.6;

/* ALERT AUDIO: will be played when pomodoro completes */
const alertAudio = new Audio("assets/music/alert.opus");
alertAudio.preload = "auto";
alertAudio.volume = 0.9;
// expose globally so startPomo can access it safely (used with try/catch)
window.alertAudio = alertAudio;

$("#musicPlay").on("click", () => {
  if (audio.paused) {
    audio.play();
    $("#musicPlay").text("Pause");
  } else {
    audio.pause();
    $("#musicPlay").text("Play");
  }
});
$("#musicSelect").on("change", function () {
  const m = $(this).val();
  // MAPPING UPDATED: values correspond to actual music files in assets/music/
  const map = {
    music_1: "assets/music/music_1.opus",
    music_2: "assets/music/music_2.opus",
    music_3: "assets/music/music_3.opus",
    music_4: "assets/music/music_4.opus",
    music_5: "assets/music/music_5.opus",
  };
  audio.src = map[m] || "";
  if (audio.src && !audio.paused) audio.play();
});
$("#musicVol").on("input", function () {
  audio.volume = parseFloat($(this).val());
});

/* Fake EQ bars */
const eqCanvas = document.getElementById("musicEQ");
if (eqCanvas) {
  const eq = eqCanvas.getContext("2d");
  function drawEQ() {
    eq.clearRect(0, 0, eqCanvas.width, eqCanvas.height);
    const bars = 20;
    const w = eqCanvas.width / bars;
    for (let i = 0; i < bars; i++) {
      const h = Math.random() * eqCanvas.height;
      eq.fillStyle = "rgba(124,58,237,0.8)";
      eq.fillRect(i * w + 4, eqCanvas.height - h, w - 6, h);
    }
  }
  setInterval(drawEQ, 160);
}

/* ---------- Sticky notes ---------- */
let notes = getCookie("focumi_notes") || [];
function renderNotes() {
  $("#notesArea").empty();
  notes.forEach((n, idx) => {
    const el = $(
      `<div class="note-card" data-id="${idx}" 
         style="left:${n.x}px;top:${n.y}px;background:${n.color ||
        "#fff7b2"}">
           <div class="note-text" contenteditable>${n.text}</div>
           <div class="d-flex justify-content-end mt-1">
             <button class="btn btn-sm btn-danger del-note">Del</button>
           </div>
       </div>`
    );
    $("#notesArea").append(el);
    makeDraggable(el[0]);
  });
}
function saveNotes() {
  setCookie("focumi_notes", notes);
}
$("#addNote").on("click", () => {
  notes.push({
    text: "New note",
    x: 30 + notes.length * 12,
    y: 30 + notes.length * 12,
    color: "#fff7b2",
  });
  saveNotes();
  renderNotes();
});
$("#notesArea").on("click", ".del-note", function () {
  const id = $(this).closest(".note-card").data("id");
  notes.splice(id, 1);
  saveNotes();
  renderNotes();
});

let globalDragging = false;

function makeDraggable(el) {
  const container = document.getElementById("notesArea");
  el.addEventListener("mousedown", startDrag);
  el.addEventListener("touchstart", startDrag, { passive: false });

  function startDrag(e) {
    // FIX: if the user clicked inside the editable text area, allow normal focus/edit
    const targetElem = (e.touches && e.touches[0] && e.touches[0].target) || e.target;

    // Do not start drag when interacting with interactive elements (buttons/inputs/links/textarea/note text).
    // This prevents touchstart from calling preventDefault and blocking the subsequent click on mobile.
    if (
      targetElem &&
      targetElem.closest &&
      (targetElem.closest(".note-text") ||
        targetElem.closest("button") ||
        targetElem.closest(".del-note") ||
        targetElem.closest("input") ||
        targetElem.closest("textarea") ||
        targetElem.closest("a"))
    ) {
      // do not start drag when interacting with the editable content or controls
      return;
    }

    // proceed with drag behavior for the note card
    // prevent default only when starting a drag on the card itself (not on inner editable or interactive elements)
    e.preventDefault();
    globalDragging = true;
    const rectC = container.getBoundingClientRect();
    const rect = el.getBoundingClientRect();
    const startX = e.touches ? e.touches[0].clientX : e.clientX;
    const startY = e.touches ? e.touches[0].clientY : e.clientY;
    const offsetX = startX - rect.left;
    const offsetY = startY - rect.top;

    function moveAt(pageX, pageY) {
      let newLeft = pageX - rectC.left - offsetX;
      let newTop = pageY - rectC.top - offsetY;
      newLeft = Math.max(0, Math.min(newLeft, rectC.width - rect.width));
      newTop = Math.max(0, Math.min(newTop, rectC.height - rect.height));
      el.style.left = newLeft + "px";
      el.style.top = newTop + "px";
    }

    function onMove(ev) {
      const cx = ev.touches ? ev.touches[0].clientX : ev.clientX;
      const cy = ev.touches ? ev.touches[0].clientY : ev.clientY;
      moveAt(cx, cy);
    }
    function onUp() {
      globalDragging = false;
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("touchmove", onMove);
      document.removeEventListener("mouseup", onUp);
      document.removeEventListener("touchend", onUp);
      const idn = parseInt(el.dataset.id, 10);
      notes[idn].x = parseInt(el.style.left, 10);
      notes[idn].y = parseInt(el.style.top, 10);
      notes[idn].text = el.querySelector(".note-text").innerText;
      saveNotes();
    }

    document.addEventListener("mousemove", onMove);
    document.addEventListener("touchmove", onMove, { passive: false });
    document.addEventListener("mouseup", onUp);
    document.addEventListener("touchend", onUp);
  }
}
renderNotes();

/* Export notes PNG */
$("#exportNotes").on("click", () => {
  const area = document.getElementById("notesArea");
  if (!area) return alert("Area catatan tidak ditemukan");
  html2canvas(area, { useCORS: true, scale: 2 })
    .then((canvas) => {
      const link = document.createElement("a");
      link.download = "focumi_notes.png";
      link.href = canvas.toDataURL("image/png");
      link.click();
    })
    .catch((err) => alert("Export gagal: " + err));
});

/* ---------- Random Wheel ---------- */
let wheelSpinning = false;

/* Render a visual wheel into the canvas based on current todos (task texts) */
function renderWheel() {
  const canvas = document.getElementById("wheelCanvas");
  if (!canvas) return;
  // ensure CSS sizing is used; adjust canvas internal pixel buffer for DPR
  const rect = canvas.getBoundingClientRect();
  const size = Math.min(rect.width, rect.height) || 240;
  const dpr = window.devicePixelRatio || 1;
  canvas.width = size * dpr;
  canvas.height = size * dpr;
  canvas.style.width = size + "px";
  canvas.style.height = size + "px";

  const ctx = canvas.getContext("2d");
  ctx.setTransform(1, 0, 0, 1, 0, 0); // reset any transforms
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.scale(dpr, dpr);

  const tasks = (getCookie("focumi_todos") || []).map((t) => t.text);
  const cx = size / 2;
  const cy = size / 2;
  const r = size / 2 - 6;

  if (!tasks.length) {
    // draw placeholder circle
    ctx.beginPath();
    ctx.fillStyle = "#ffffff";
    ctx.arc(cx, cy, r, 0, Math.PI * 2);
    ctx.fill();
    ctx.fillStyle = "#999";
    ctx.font = "14px Inter, sans-serif";
    ctx.textAlign = "center";
    ctx.fillText("No tasks", cx, cy + 4);
    return;
  }

  const segCount = tasks.length;
  const segAngle = (Math.PI * 2) / segCount;
  for (let i = 0; i < segCount; i++) {
    const start = -Math.PI / 2 + i * segAngle;
    const end = start + segAngle;
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.arc(cx, cy, r, start, end);
    ctx.closePath();
    // alternating colors for readability
    ctx.fillStyle = i % 2 === 0 ? "#7c3aed" : "#93c5fd";
    ctx.fill();

    // draw label
    ctx.save();
    ctx.translate(cx, cy);
    const mid = (start + end) / 2;
    ctx.rotate(mid);
    ctx.fillStyle = "rgba(255,255,255,0.95)";
    ctx.font = "12px Inter, sans-serif";
    ctx.textAlign = "right";
    const label = tasks[i].length > 20 ? tasks[i].slice(0, 17) + "…" : tasks[i];
    ctx.fillText(label, r - 8, 4);
    ctx.restore();
  }

  // center badge
  ctx.beginPath();
  ctx.fillStyle = "#fff";
  ctx.arc(cx, cy, 34, 0, Math.PI * 2);
  ctx.fill();
  ctx.fillStyle = "#333";
  ctx.font = "bold 12px Inter, sans-serif";
  ctx.textAlign = "center";
  ctx.fillText("Focumi", cx, cy + 4);
}

// call render initially and on resize
renderWheel();
window.addEventListener("resize", () => {
  renderWheel();
});

$("#spinWheel").on("click", () => {
  if (wheelSpinning) return;
  const taskList = (getCookie("focumi_todos") || []).map((t) => t.text);
  if (!taskList.length) return alert("Tambahkan beberapa task terlebih dahulu");
  wheelSpinning = true;

  const segCount = taskList.length;
  const segAngle = 360 / segCount;

  const randomIndex = Math.floor(Math.random() * segCount);
  const centerAngleForIndex =
    (360 - randomIndex * segAngle - segAngle / 2) % 360;
  const rot = 360 * 6 + centerAngleForIndex;

  $("#wheelCanvas").css({
    transition: "transform 4s cubic-bezier(.1,.8,.2,1)",
    transform: "rotate(" + rot + "deg)",
  });

  setTimeout(() => {
    wheelSpinning = false;
    const chosen = taskList[randomIndex];
    notify("Wheel pilih: " + chosen);

    // reset transform (no animation) so wheel is visually back to initial state for next spin
    $("#wheelCanvas").css({
      transition: "none",
      transform: "rotate(0deg)",
    });
  }, 4200);
});

/* ---------- Mood Tracker + Mood Modal ---------- */
let moodData = getCookie("focumi_mood") || [];
const moodCanvas = document.getElementById("moodChart");
let moodChart;
let renderMoodChart = () => {};
if (moodCanvas) {
  const moodCtx = moodCanvas.getContext("2d");
  moodChart = new Chart(moodCtx, {
    type: "bar",
    data: {
      labels: [],
      datasets: [
        {
          label: "Mood",
          data: [],
          backgroundColor: "#93c5fd",
        },
      ],
    },
    options: {
      scales: { y: { min: 0, max: 5 } },
    },
  });

  renderMoodChart = function () {
    const labels = moodData.map((d) => d.date);
    const data = moodData.map((d) => d.score);
    moodChart.data.labels = labels;
    moodChart.data.datasets[0].data = data;
    moodChart.update();
  };

  $(".mood-btn").on("click", function () {
    const score = parseInt($(this).data("mood"), 10);
    const date = new Date().toISOString().slice(0, 10);
    moodData.push({ date, score });
    setCookie("focumi_mood", moodData);
    renderMoodChart();
    updateDashboard();

    // show a random quote centered after selecting mood (widget buttons)
    const q = quotes[Math.floor(Math.random() * quotes.length)];
    // show centered modal for a short duration (now top-center via CSS)
    showQuoteModal(q, { timeout: 3800 });

    // play mood music via main music widget/player (connect mood -> music widget)
    try {
      playMoodMusic(score);
    } catch (e) {
      // non-critical
    }
  });
  renderMoodChart();
}

/* Mood modal handlers: small centered modal that triggers mood-backed music */
const bgAudio = new Audio();
bgAudio.loop = true;
bgAudio.volume = 0.45;
/* Mood->music mapping
   NOTE: files ordered 1..5 correspond to happy..angry per request.
   We'll route mood playback through the main 'audio' player so it's controlled by the Music widget.
*/
const moodTracks = {
  5: "assets/music/music_1.opus", // happy
  4: "assets/music/music_2.opus",
  3: "assets/music/music_3.opus",
  2: "assets/music/music_4.opus",
  1: "assets/music/music_5.opus", // angry
};
function closeMoodModal() {
  $("#moodModal").fadeOut();
}
function openMoodModal() {
  $("#moodModal").fadeIn();
}

/* Helper: play mood music using main audio player so widget music is connected */
function playMoodMusic(score) {
  const src = moodTracks[score];
  if (!src) return;
  try {
    // set main audio source (widget uses 'audio' variable)
    audio.src = src;
    // update musicSelect UI to empty/none (we map mood-play separately)
    $("#musicSelect").val("");
    // try to play (user interaction from click allows playback)
    audio.play().then(() => {
      $("#musicPlay").text("Pause");
    }).catch(() => {
      // autoplay may be blocked, ensure UI shows Play so user can trigger
      $("#musicPlay").text("Pause");
    });
  } catch (e) {
    // ignore non-fatal errors
  }
}

/* bind modal buttons */
$(document).on("click", ".modal-mood-btn", function () {
  const score = parseInt($(this).data("mood"), 10);
  const date = new Date().toISOString().slice(0, 10);
  moodData.push({ date, score });
  setCookie("focumi_mood", moodData);
  renderMoodChart();
  setCookie("focumi_mood_set_today", true);

  // play mood music via main player (connected to Music widget)
  try {
    playMoodMusic(score);
  } catch (e) {
    // ignore
  }

  // show a random quote centered after selecting mood (modal buttons)
  const q = quotes[Math.floor(Math.random() * quotes.length)];
  showQuoteModal(q, { timeout: 3800 });

  notify("Terima kasih! Mood disimpan.");
  closeMoodModal();
  updateDashboard();
});

/* skip button */
$("#skipMood").on("click", function () {
  setCookie("focumi_mood_set_today", true);
  closeMoodModal();
});

/* initial modal show (if not set) */
$(document).ready(function () {
  if (!getCookie("focumi_mood_set_today")) {
    setTimeout(openMoodModal, 600);
  }
});

/* Focus Room */
function openFocusRoom() {
  $("#focusRoom").fadeIn();
  $("#focusTimer").text($("#pomoDisplay").text());
}
function closeFocusRoom() {
  $("#focusRoom").fadeOut();
}
$("#open-focus-room").on("click", openFocusRoom);
$("#exitFocus").on("click", closeFocusRoom);

/* Default cookies */
if (!getCookie("focumi_todos")) setCookie("focumi_todos", []);
if (!getCookie("focumi_notes")) setCookie("focumi_notes", []);

/* Responsive tweak */
if (window.innerWidth < 768) {
  // no-op: handled by CSS; kept for backward compat
}

/* Mood ambience, parallax, glint (refined) */
$(document).ready(function () {
  const $parallaxBg = $("#parallax-bg");
  const orbColors = [
    "rgba(124, 58, 237, 0.35)",
    "rgba(56, 189, 248, 0.28)",
    "rgba(236, 72, 153, 0.25)",
  ];
  for (let i = 0; i < 3; i++) {
    const $orb = $('<div class="parallax-orb"></div>');
    $orb.css({
      width: Math.floor(Math.random() * 200 + 260) + "px",
      height: Math.floor(Math.random() * 200 + 260) + "px",
      background: orbColors[i % orbColors.length],
      top: Math.random() * 80 + "vh",
      left: Math.random() * 80 + "vw",
      "--data-speed": Math.random() * 30 + 10,
    });
    $parallaxBg.append($orb);
  }

  $(document).on("mousemove", function (e) {
    const percentX = e.clientX / window.innerWidth - 0.5;
    const percentY = e.clientY / window.innerHeight - 0.5;
    $(".parallax-orb").each(function () {
      const speed = parseFloat($(this).css("--data-speed")) || 20;
      const moveX = percentX * speed * -1;
      const moveY = percentY * speed * -1;
      $(this).css("transform", `translate(${moveX}px, ${moveY}px)`);
    });
  });

  // widget glint: only active when not dragging and when target is not interactive
  $(".widget").prepend('<div class="widget-glint"></div>');
  $(".widget").on("mousemove", function (e) {
    if (globalDragging) return;
    const interactiveSelectors = "input, textarea, .note-card, .time-block, .handle, .modal-mood-btn, .form-range, select, button";
    if ($(e.target).closest(interactiveSelectors).length) return;
    const $widget = $(this);
    const $glint = $widget.find(".widget-glint");
    const rect = this.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const rotateY = ((x - rect.width / 2) / (rect.width / 2)) * 6; // reduced tilt
    const rotateX = ((y - rect.height / 2) / (rect.height / 2)) * -6;
    $widget.css(
      "transform",
      `rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.02)`
    );
    $glint.css({ left: x + "px", top: y + "px", display: "block", opacity: 0.9 });
  });
  $(".widget").on("mouseleave", function () {
    const $widget = $(this);
    if (globalDragging) return;
    $widget.css("transform", "rotateX(0deg) rotateY(0deg) scale(1)");
    $widget.find(".widget-glint").css("display", "none");
  });

  // initial layout/visibility applied after small delay
  setTimeout(() => {
    applyLayoutOrder();
    applyVisibilityMap(getCookie("focumi_visibility"));
  }, 120);
});

/* Notifications */
function notify(msg, timeout = 3000) {
  const $n = $(`<div class="focumi-toast">${msg}</div>`).appendTo("body");
  setTimeout(() => {
    $n.addClass("visible");
  }, 20);
  setTimeout(() => {
    $n.removeClass("visible");
    setTimeout(() => $n.remove(), 300);
  }, timeout);
}

/* Dashboard */
function updateDashboard() {
  const focusedMins =
    pomo && (pomo.completedCycles ? (pomo.completedCycles * (pomo.mode || 25)) : 0);
  const doneCount = (todos || []).filter((t) => t.done).length;
  const habitCount = (moodData || []).length;
  $("#dash-focused").text(focusedMins);
  $("#dash-done").text(doneCount);
  $("#dash-habit").text(habitCount);

  const barCtx =
    document.getElementById("dashBar") &&
    document.getElementById("dashBar").getContext("2d");
  if (barCtx) {
    const labels = moodData.slice(-7).map((d) => d.date);
    const data = moodData.slice(-7).map((d) => d.score);
    if (!window._dashBar)
      window._dashBar = new Chart(barCtx, {
        type: "bar",
        data: {
          labels,
          datasets: [
            {
              label: "Mood (last7)",
              data,
              backgroundColor: "rgba(124,58,237,0.6)",
            },
          ],
        },
        options: {
          scales: { y: { min: 0, max: 5 } },
        },
      });
    else {
      window._dashBar.data.labels = labels;
      window._dashBar.data.datasets[0].data = data;
      window._dashBar.update();
    }
  }

  const pieCtx =
    document.getElementById("dashPie") &&
    document.getElementById("dashPie").getContext("2d");
  if (pieCtx) {
    const total = todos.length || 1;
    const done = doneCount;
    const rem = Math.max(0, total - done);
    if (!window._dashPie)
      window._dashPie = new Chart(pieCtx, {
        type: "pie",
        data: {
          labels: ["Done", "Remaining"],
          datasets: [
            {
              data: [done, rem],
              backgroundColor: ["#7c3aed", "#93c5fd"],
            },
          ],
        },
      });
    else {
      window._dashPie.data.datasets[0].data = [done, rem];
      window._dashPie.update();
    }
  }
}
updateDashboard();

/* =================================================
   MINI CALENDAR (REPLACES PLANNER)
   - events stored in cookie 'focumi_events' as { "YYYY-MM-DD": [{title,time,id}, ...], ... }
   - click day to select, Add Event button to create
   - simple modal for create/edit
   ================================================= */
let eventsStore = getCookie("focumi_events") || {}; // object keyed by date
let selectedDate = new Date();
const calGrid = document.getElementById("calendarGrid");
const calLabel = document.getElementById("calLabel");
const eventList = document.getElementById("eventList");
const eventModal = $("#eventModal");
const eventDateInput = $("#eventDate");
const eventTimeInput = $("#eventTime");
const eventTitleInput = $("#eventTitle");
let editingEventId = null;

function formatDateKey(d) {
  if (!d) return null;
  const yyyy = d.getFullYear();
  const mm = String(d.getMonth() + 1).padStart(2, "0");
  const dd = String(d.getDate()).padStart(2, "0");
  return `${yyyy}-${mm}-${dd}`;
}

function saveEventsStore() {
  setCookie("focumi_events", eventsStore);
}

function renderCalendar(referenceDate = new Date()) {
  if (!calGrid) return;
  const viewDate = new Date(referenceDate.getFullYear(), referenceDate.getMonth(), 1);
  const month = viewDate.getMonth();
  const year = viewDate.getFullYear();
  calLabel.innerText = viewDate.toLocaleString("id-ID", { month: "long", year: "numeric" });

  // Clear grid and add weekday labels
  calGrid.innerHTML = "";
  const weekdays = ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"];
  weekdays.forEach((w) => {
    const lbl = document.createElement("div");
    lbl.className = "calendar-weekday-label";
    lbl.innerText = w;
    calGrid.appendChild(lbl);
  });

  // compute first day index and days in month
  const firstDayIndex = new Date(year, month, 1).getDay(); // 0..6
  const daysInMonth = new Date(year, month + 1, 0).getDate();

  // previous month's tail
  const prevMonthDays = new Date(year, month, 0).getDate();

  // total cells to show (to fill 6 rows sometimes)
  const totalCells = 42; // 6 x 7 for consistent layout

  for (let i = 0; i < totalCells; i++) {
    const cell = document.createElement("div");
    cell.className = "calendar-cell";
    let dayNum = 0;
    let cellDate = null;
    if (i < firstDayIndex) {
      // prev month
      dayNum = prevMonthDays - (firstDayIndex - 1 - i);
      cell.classList.add("other-month");
      cellDate = new Date(year, month - 1, dayNum);
    } else if (i >= firstDayIndex + daysInMonth) {
      // next month
      dayNum = i - (firstDayIndex + daysInMonth) + 1;
      cell.classList.add("other-month");
      cellDate = new Date(year, month + 1, dayNum);
    } else {
      dayNum = i - firstDayIndex + 1;
      cellDate = new Date(year, month, dayNum);
      // highlight today
      const today = new Date();
      if (today.toDateString() === cellDate.toDateString()) {
        cell.style.boxShadow = "0 0 0 2px rgba(124,58,237,0.12) inset";
      }
    }
    const num = document.createElement("div");
    num.className = "calendar-day-num";
    num.innerText = dayNum;
    cell.appendChild(num);

    // events indicator
    const k = formatDateKey(cellDate);
    const evs = eventsStore[k] || [];
    if (evs.length) {
      const dotsWrap = document.createElement("div");
      dotsWrap.style.position = "absolute";
      dotsWrap.style.bottom = "6px";
      dotsWrap.style.left = "6px";
      evs.slice(0, 3).forEach(() => {
        const dot = document.createElement("span");
        dot.className = "event-dot";
        dotsWrap.appendChild(dot);
      });
      if (evs.length > 3) {
        const more = document.createElement("span");
        more.className = "small text-muted";
        more.style.marginLeft = "4px";
        more.innerText = "+" + (evs.length - 3);
        dotsWrap.appendChild(more);
      }
      cell.appendChild(dotsWrap);
    }

    // click handler: select date and show events
    (function (d) {
      cell.addEventListener("click", function () {
        selectedDate = d;
        renderEventsForSelected();
        // center-select visual
        $("#calendarGrid .calendar-cell").css("outline", "none");
        $(cell).css("outline", "2px solid rgba(124,58,237,0.12)");
      });
    })(cellDate);

    calGrid.appendChild(cell);
  }

  // After render, if previously selected month -> keep selection or set to first of month
  if (selectedDate.getMonth() !== month || selectedDate.getFullYear() !== year) {
    selectedDate = new Date(year, month, 1);
  }
  renderEventsForSelected();
}

function renderEventsForSelected() {
  if (!eventList) return;
  const k = formatDateKey(selectedDate);
  $("#eventList").empty();
  const header = $("<div class='fw-semibold mb-1'></div>").text(selectedDate.toLocaleDateString("id-ID", { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }));
  $("#eventList").append(header);
  const evs = eventsStore[k] || [];
  if (!evs.length) {
    $("#eventList").append('<li class="list-group-item small text-muted">Belum ada events</li>');
  } else {
    evs.forEach((ev) => {
      const li = $(`<li class="list-group-item d-flex justify-content-between align-items-center small"></li>`);
      const left = $(`<div><div class="fw-semibold">${ev.title}</div><div class="text-muted small">${ev.time || ""}</div></div>`);
      const right = $(`<div></div>`);
      const del = $(`<button class="btn btn-sm btn-outline-danger btn-delete-event">Hapus</button>`);
      del.on("click", function () {
        deleteEventById(k, ev.id);
      });
      right.append(del);
      li.append(left, right);
      $("#eventList").append(li);
    });
  }
  // ensure calendar selection visual
  $("#calendarGrid .calendar-cell").each(function () {
    const cellNum = $(this).find(".calendar-day-num").text();
    // rough match by date number and month/year
    const cellIndex = $(this).index(); // includes weekday labels; we used fixed layout but styling is consistent
  });
}

function addEvent(dateKey, title, time) {
  if (!dateKey || !title) return;
  const entry = { id: "e_" + Date.now() + "_" + Math.floor(Math.random() * 999), title, time: time || "" };
  eventsStore[dateKey] = eventsStore[dateKey] || [];
  eventsStore[dateKey].push(entry);
  saveEventsStore();
  renderCalendar(selectedDate);
  notify("Event tersimpan");
}

function deleteEventById(dateKey, id) {
  if (!eventsStore[dateKey]) return;
  eventsStore[dateKey] = eventsStore[dateKey].filter((e) => e.id !== id);
  if (!eventsStore[dateKey].length) delete eventsStore[dateKey];
  saveEventsStore();
  renderCalendar(selectedDate);
  notify("Event dihapus");
}

/* Buttons: prev/next month */
$("#calPrev").on("click", function () {
  selectedDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth() - 1, 1);
  renderCalendar(selectedDate);
});
$("#calNext").on("click", function () {
  selectedDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth() + 1, 1);
  renderCalendar(selectedDate);
});

/* Add Event modal flow */
$("#addEventBtn").on("click", function () {
  openEventModal();
});
$("#clearEventsBtn").on("click", function () {
  if (!confirm("Hapus semua events?")) return;
  eventsStore = {};
  saveEventsStore();
  renderCalendar(selectedDate);
  renderEventsForSelected();
  notify("Semua event dihapus");
});

function openEventModal(date) {
  editingEventId = null;
  const d = date ? new Date(date) : selectedDate;
  const key = formatDateKey(d);
  eventDateInput.val(key);
  eventTimeInput.val("");
  eventTitleInput.val("");
  eventModal.fadeIn();
}

$("#cancelEventBtn").on("click", function () {
  eventModal.fadeOut();
});

$("#saveEventBtn").on("click", function () {
  const dateVal = eventDateInput.val();
  const timeVal = eventTimeInput.val();
  const titleVal = eventTitleInput.val().trim();
  if (!dateVal || !titleVal) return alert("Isi tanggal dan judul event");
  addEvent(dateVal, titleVal, timeVal);
  eventModal.fadeOut();
  renderEventsForSelected();
});

/* Clicking a day sets selectedDate — we also allow quick add by doubleclick */
$(document).on("dblclick", ".calendar-cell", function () {
  const day = $(this).find(".calendar-day-num").text();
  const currentLabel = calLabel.innerText.split(" ");
  // pick month/year from calLabel using stored selectedDate
  openEventModal(selectedDate);
});

/* Initial render */
renderCalendar(selectedDate);

/* ---------- Ambience particle effects (snow, rain) ---------- */
const ambienceCanvas = document.getElementById("ambience-canvas");
const ambienceCtx = ambienceCanvas && ambienceCanvas.getContext("2d");
let ambienceParticles = [];
let ambienceMode = getCookie("focumi_ambience") || "none";

function resizeAmbienceCanvas() {
  if (!ambienceCanvas) return;
  // keep CSS size in sync and set canvas pixel buffer to match CSS pixels
  ambienceCanvas.style.width = window.innerWidth + "px";
  ambienceCanvas.style.height = window.innerHeight + "px";
  ambienceCanvas.width = window.innerWidth;
  ambienceCanvas.height = window.innerHeight;
}
resizeAmbienceCanvas();
window.addEventListener("resize", resizeAmbienceCanvas);

/* ensure the UI select reflects saved ambience mode on load */
if (typeof $ !== "undefined" && $("#ambiencePicker").length) {
  $("#ambiencePicker").val(ambienceMode);
}

$("#ambiencePicker").on("change", function () {
  ambienceMode = $(this).val();
  setCookie("focumi_ambience", ambienceMode);
  setupAmbience(ambienceMode);
});

function setupAmbience(mode) {
  ambienceParticles = [];
  if (mode === "snow") {
    for (let i = 0; i < 140; i++) {
      ambienceParticles.push({
        x: Math.random() * window.innerWidth,
        y: Math.random() * window.innerHeight,
        r: Math.random() * 3 + 1,
        vx: Math.random() * 0.6 - 0.3,
        vy: Math.random() * 0.6 + 0.3,
        alpha: 0.7,
      });
    }
  } else if (mode === "rain") {
    // create slender raindrops with slight horizontal drift for realism
    for (let i = 0; i < 200; i++) {
      ambienceParticles.push({
        x: Math.random() * window.innerWidth,
        y: Math.random() * window.innerHeight,
        w: Math.random() * 1.6 + 0.6,
        h: Math.random() * 12 + 8,
        vx: Math.random() * 0.8 - 0.4, // small horizontal drift
        vy: Math.random() * 4 + 4,
        alpha: 0.65,
      });
    }
  } else {
    // none -> keep particles empty
  }
}
setupAmbience(ambienceMode);

function tickAmbience() {
  if (!ambienceCtx) return;
  // clear using full canvas size
  ambienceCtx.clearRect(0, 0, ambienceCanvas.width, ambienceCanvas.height);

  if (ambienceMode === "snow") {
    ambienceCtx.fillStyle = "rgba(255,255,255,0.8)";
    ambienceParticles.forEach((p) => {
      p.x += p.vx;
      p.y += p.vy;
      if (p.y > ambienceCanvas.height) {
        p.y = -10;
        p.x = Math.random() * ambienceCanvas.width;
      }
      ambienceCtx.beginPath();
      ambienceCtx.globalAlpha = p.alpha;
      ambienceCtx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
      ambienceCtx.fill();
    });
    ambienceCtx.globalAlpha = 1;
  } else if (ambienceMode === "rain") {
    // draw slanted raindrops that are visible on light backgrounds
    ambienceCtx.strokeStyle = "rgba(120,150,180,0.45)";
    ambienceCtx.lineWidth = 1.2;
    ambienceParticles.forEach((p) => {
      p.x += p.vx;
      p.y += p.vy;
      // reset when out of bounds
      if (p.y > ambienceCanvas.height + 30 || p.x < -50 || p.x > ambienceCanvas.width + 50) {
        p.y = -20;
        p.x = Math.random() * ambienceCanvas.width;
      }
      ambienceCtx.globalAlpha = p.alpha;
      ambienceCtx.beginPath();
      // slightly slanted drop to simulate wind
      ambienceCtx.moveTo(p.x, p.y);
      ambienceCtx.lineTo(p.x + (p.vx * 4), p.y + p.h);
      ambienceCtx.stroke();
    });
    ambienceCtx.globalAlpha = 1;
  }
  requestAnimationFrame(tickAmbience);
}
tickAmbience();

/* ---------- Widget interaction improvements (disable glint while interacting) ---------- */
/* globalDragging flag used earlier (set to true during note / timeline drag) */

/* ---------- Helpers ---------- */
function clamp(v, a, b) {
  return Math.max(a, Math.min(b, v));
}

/* Persist default storages if missing */
if (!getCookie("focumi_events")) setCookie("focumi_events", {});
if (!getCookie("focumi_todos")) setCookie("focumi_todos", []);
if (!getCookie("focumi_notes")) setCookie("focumi_notes", []);

/* Make sure wheel updates when todos change (we already call renderWheel inside renderTodos) */
updateDashboard();

/* ---------------------------
   Adjusted quote display usage
   - Use showQuoteModal(...) for 'inspire' and initial random quote so
     all quote appearances are top-center (CSS handles placement).
---------------------------- */

/* ---------- Quotes / Inspire binding updates ---------- */
$("#inspire").on("click", () => {
  const q = quotes[Math.floor(Math.random() * quotes.length)];
  typeQuote(q); // still set widget quote box
  // show top-center modal for quotes (auto-hide)
  showQuoteModal(q, { timeout: 3800 });
});

/* show a random quote as top-center modal on load (instead of top-right toast) */
$(document).ready(function () {
  const q = quotes[Math.floor(Math.random() * quotes.length)];
  showQuoteModal(q, 3800);
});

/* ============================================================
   RESPONSIVE HEADER MENU LOGIC
   - Moves .feature-toggles and .controls into #mobileMenu on small screens
   - Toggling #menuToggle slides the mobile menu
   - Clicking outside closes the mobile menu
   IMPORTANT: elements are moved (not cloned) so event handlers remain intact.
   ============================================================ */
(function () {
  const MOBILE_BREAK = 768;
  const $menuToggle = $("#menuToggle");
  const $mobileMenu = $("#mobileMenu");
  const $featureToggles = $(".feature-toggles");
  const $controls = $(".controls");

  function applyResponsiveMove() {
    if ($(window).width() <= MOBILE_BREAK) {
      // move elements into mobile menu if not already moved
      if (!$mobileMenu.data("moved")) {
        $mobileMenu.append($featureToggles, $controls);
        $mobileMenu.data("moved", true);
      }
      $menuToggle.show();
    } else {
      // move back to header (after brand)
      if ($mobileMenu.data("moved")) {
        $(".topbar .brand").after($featureToggles);
        $(".topbar .brand").after($controls);
        $mobileMenu.data("moved", false);
        $mobileMenu.hide();
      }
      $menuToggle.hide();
    }
  }

  // initial apply
  $(document).ready(function () {
    applyResponsiveMove();
  });

  // on resize
  $(window).on("resize", function () {
    applyResponsiveMove();
  });

  // toggle button
  $menuToggle.on("click", function (e) {
    e.stopPropagation();
    const isVisible = $mobileMenu.is(":visible");
    if (isVisible) {
      $mobileMenu.slideUp(160);
      $menuToggle.attr("aria-expanded", "false").removeClass("open");
    } else {
      $mobileMenu.slideDown(160);
      $menuToggle.attr("aria-expanded", "true").addClass("open");
    }
  });

  // close when clicking outside
  $(document).on("click", function (e) {
    if ($mobileMenu.is(":visible") && !$(e.target).closest("#mobileMenu, #menuToggle").length) {
      $mobileMenu.slideUp(160);
      $menuToggle.attr("aria-expanded", "false").removeClass("open");
    }
  });

  // ensure menu is hidden on orientation change to avoid layout issues
  window.addEventListener("orientationchange", function () {
    $mobileMenu.hide();
    $menuToggle.removeClass("open").attr("aria-expanded", "false");
  });
})();