// ── Scheduling (modal + RPC poller only) ────────────────────────────────────
// Stage C of the Dynamic Glass Panel arc — see ~/Documents/dynamic-glass-panel.md.
//
// Before Stage C this file owned the SCHEDULING sticky panel: list
// rendering, toggle controls, count badge, Add button. The sticky panel
// is gone; scheduled jobs now surface in the AWAITING footer
// (glass-ui/js/symframe-awaiting.js).
//
// What survives here:
//   - The schedule create/edit modal (overlay + form + submit handler)
//   - The fetchSchedules poll loop (30s + gateway:connected)
//   - window.schedulingPanel exported API:
//       refresh()            — force a fetch
//       open()               — open the create modal
//       openForEdit(job)     — open the modal pre-filled for a job
//       getActive()          — current schedules snapshot
//       toggle(jobId)        — enable/disable a job via cron.update
//   - CustomEvent dispatch after each successful fetch so the AWAITING
//     surface re-renders without polling a parallel copy of the same RPC.
// ─────────────────────────────────────────────────────────────────────────────

"use strict";

(function () {
  // ── State ──
  let schedules = [];
  let selectedInterval = null;
  let editingScheduleId = null;
  let _pollInterval = null;

  // ── Modal DOM refs (separate overlay block in index.html) ──
  const modalOverlay = document.getElementById("schedule-modal-overlay");
  const modalClose = document.getElementById("schedule-modal-close");
  const modalCancel = document.getElementById("schedule-modal-cancel");
  const modalSubmit = document.getElementById("schedule-modal-submit");
  const nameInput = document.getElementById("schedule-name");
  const taskInput = document.getElementById("schedule-task");
  const intervalBtns = document.querySelectorAll(".schedule-interval-btn");
  const customOptions = document.getElementById("schedule-custom-options");
  const intervalValueInput = document.getElementById("schedule-interval-value");
  const intervalUnitSelect = document.getElementById("schedule-interval-unit");
  const timeInput = document.getElementById("schedule-time");

  // ── Interval helpers ──
  const UNIT_TO_MS = {
    minutes: 60 * 1000,
    hours: 60 * 60 * 1000,
    days: 24 * 60 * 60 * 1000,
    weeks: 7 * 24 * 60 * 60 * 1000,
  };

  const PRESETS = {
    hourly: { value: 1, unit: "hours" },
    daily: { value: 1, unit: "days" },
    weekly: { value: 1, unit: "weeks" },
  };

  // ── Fetch + notify ──
  async function fetchSchedules() {
    if (!window.gateway?.connected) {
      return;
    }
    try {
      const result = await window.gateway.rpc("cron.list", { includeDisabled: true });
      if (result?.jobs) {
        schedules = result.jobs;
        window.dispatchEvent(new CustomEvent("symi:schedules-updated", { detail: { schedules } }));
      }
    } catch (err) {
      console.debug("[scheduling] Failed to fetch:", err.message);
    }
  }

  async function toggleSchedule(jobId) {
    const job = schedules.find((s) => s.id === jobId);
    if (!job) {
      return;
    }
    const newEnabled = !job.enabled;
    try {
      if (window.gateway?.connected) {
        await window.gateway.rpc("cron.update", {
          id: jobId,
          patch: { enabled: newEnabled },
        });
      }
      job.enabled = newEnabled;
      window.dispatchEvent(new CustomEvent("symi:schedules-updated", { detail: { schedules } }));
    } catch (err) {
      console.error("[scheduling] Toggle failed:", err);
    }
  }

  // ── Modal ──
  function openModal() {
    if (!modalOverlay) {
      return;
    }
    editingScheduleId = null;
    selectedInterval = null;
    resetForm();
    modalOverlay.classList.add("open");
    modalOverlay.setAttribute("aria-hidden", "false");
    nameInput?.focus();
    document.addEventListener("keydown", onModalKey);
  }

  function openModalForEdit(job) {
    if (!modalOverlay || !nameInput) {
      return;
    }
    editingScheduleId = job.id;
    nameInput.value = job.name || "";
    if (taskInput) {
      taskInput.value = job.payload?.message || "";
    }
    const schedule = job.schedule;
    if (schedule?.kind === "every") {
      const ms = schedule.everyMs;
      if (ms === UNIT_TO_MS.hours) {
        selectInterval("hourly");
      } else if (ms === UNIT_TO_MS.days) {
        selectInterval("daily");
      } else if (ms === UNIT_TO_MS.weeks) {
        selectInterval("weekly");
      } else {
        selectInterval("custom");
        if (ms % UNIT_TO_MS.weeks === 0) {
          intervalValueInput.value = ms / UNIT_TO_MS.weeks;
          intervalUnitSelect.value = "weeks";
        } else if (ms % UNIT_TO_MS.days === 0) {
          intervalValueInput.value = ms / UNIT_TO_MS.days;
          intervalUnitSelect.value = "days";
        } else if (ms % UNIT_TO_MS.hours === 0) {
          intervalValueInput.value = ms / UNIT_TO_MS.hours;
          intervalUnitSelect.value = "hours";
        } else {
          intervalValueInput.value = ms / UNIT_TO_MS.minutes;
          intervalUnitSelect.value = "minutes";
        }
      }
    } else {
      selectInterval("custom");
    }
    modalOverlay.classList.add("open");
    modalOverlay.setAttribute("aria-hidden", "false");
    nameInput.focus();
    document.addEventListener("keydown", onModalKey);
  }

  function closeModal() {
    if (!modalOverlay) {
      return;
    }
    modalOverlay.classList.remove("open");
    modalOverlay.setAttribute("aria-hidden", "true");
    document.removeEventListener("keydown", onModalKey);
    resetForm();
    editingScheduleId = null;
  }

  function resetForm() {
    if (nameInput) {
      nameInput.value = "";
    }
    if (taskInput) {
      taskInput.value = "";
    }
    if (intervalValueInput) {
      intervalValueInput.value = "1";
    }
    if (intervalUnitSelect) {
      intervalUnitSelect.value = "days";
    }
    if (timeInput) {
      timeInput.value = "09:00";
    }
    selectedInterval = null;
    if (customOptions) {
      customOptions.style.display = "none";
    }
    intervalBtns.forEach((btn) => btn.classList.remove("selected"));
  }

  function onModalKey(e) {
    if (e.key === "Escape") {
      closeModal();
    }
  }

  function selectInterval(interval) {
    selectedInterval = interval;
    intervalBtns.forEach((btn) => {
      const btnInterval = btn.getAttribute("data-interval");
      btn.classList.toggle("selected", btnInterval === interval);
    });
    if (customOptions) {
      customOptions.style.display = interval === "custom" ? "block" : "none";
    }
  }

  // ── Save ──
  async function saveSchedule() {
    if (!nameInput || !taskInput) {
      return;
    }
    const name = nameInput.value.trim();
    const task = taskInput.value.trim();
    if (!name) {
      nameInput.focus();
      return;
    }
    if (!task) {
      taskInput.focus();
      return;
    }
    if (!selectedInterval) {
      selectInterval("daily");
    }
    let everyMs;
    if (selectedInterval === "custom") {
      const value = parseInt(intervalValueInput?.value) || 1;
      const unit = intervalUnitSelect?.value || "days";
      everyMs = value * UNIT_TO_MS[unit];
    } else {
      const preset = PRESETS[selectedInterval];
      everyMs = preset.value * UNIT_TO_MS[preset.unit];
    }
    if (modalSubmit) {
      modalSubmit.disabled = true;
    }
    try {
      if (!window.gateway?.connected) {
        throw new Error("Gateway not connected");
      }
      if (editingScheduleId) {
        await window.gateway.rpc("cron.update", {
          id: editingScheduleId,
          patch: {
            name,
            schedule: { kind: "every", everyMs },
            payload: { kind: "agentTurn", message: task },
          },
        });
      } else {
        await window.gateway.rpc("cron.add", {
          name,
          enabled: true,
          schedule: { kind: "every", everyMs },
          sessionTarget: "isolated",
          wakeMode: "now",
          payload: { kind: "agentTurn", message: task },
        });
      }
      closeModal();
      setTimeout(fetchSchedules, 300);
    } catch (err) {
      console.error("[scheduling] Save failed:", err);
      alert("Failed to save schedule: " + (err.message || "Unknown error"));
    } finally {
      if (modalSubmit) {
        modalSubmit.disabled = false;
      }
    }
  }

  // ── Init ──
  function init() {
    if (modalClose) {
      modalClose.addEventListener("click", closeModal);
    }
    if (modalCancel) {
      modalCancel.addEventListener("click", closeModal);
    }
    if (modalSubmit) {
      modalSubmit.addEventListener("click", saveSchedule);
    }
    if (modalOverlay) {
      modalOverlay.addEventListener("click", (e) => {
        if (e.target === modalOverlay) {
          closeModal();
        }
      });
    }
    intervalBtns.forEach((btn) => {
      btn.addEventListener("click", () => {
        const interval = btn.getAttribute("data-interval");
        selectInterval(interval);
      });
    });
    if (nameInput) {
      nameInput.addEventListener("keydown", (e) => {
        if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
          void saveSchedule();
        }
      });
    }

    void fetchSchedules();
    _pollInterval = setInterval(fetchSchedules, 30000);
    window.addEventListener("gateway:connected", fetchSchedules);
    window.addEventListener("gateway:hello", fetchSchedules);
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }

  // Public API — extended in Stage C with getActive() + openForEdit() +
  // toggle() so the AWAITING surface can read state, edit jobs, and
  // flip enabled flags without re-implementing the cron RPC layer.
  window.schedulingPanel = {
    refresh: fetchSchedules,
    open: openModal,
    openForEdit: openModalForEdit,
    getActive: () => [...schedules],
    toggle: toggleSchedule,
  };
})();
