// SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
//
// SPDX-License-Identifier: GPL-2.0-or-later

import type {
  SatelliteBookmark,
  SatelliteScheduleConfig,
  SatelliteScheduleEntry,
  SatelliteSchedulerApi,
  SatelliteSchedulerStatus,
} from "./satellite-types";
import type { SchedulerConfig, SchedulerService } from "./scheduler-types.js";

interface SatelliteSchedulerWindow {
  trx?: { modules?: { scheduler?: SchedulerService } };
  satScheduler?: SatelliteSchedulerApi;
  trxUi?: { notify(message: string, options: { kind: "error" }): void };
}
const satSchedulerWindow = window as unknown as SatelliteSchedulerWindow;

// Satellite Pass Scheduling UI
// Manages the satellite overlay section within the background decoding scheduler.
// Communicates with scheduler.js via a thin window API for shared state access.

(function () {
  "use strict";

  // ── DOM references (cached once) ──────────────────────────────────
  const dom = {
    enabled:    document.getElementById("scheduler-sat-enabled") as HTMLInputElement | null,
    pretune:    document.getElementById("scheduler-sat-pretune") as HTMLInputElement | null,
    body:       document.getElementById("scheduler-sat-body"),
    tbody:      document.getElementById("scheduler-sat-tbody"),
    addBtn:     document.getElementById("scheduler-sat-add-btn"),
    passStatus: document.getElementById("scheduler-sat-pass-status"),
    formWrap:   document.getElementById("sch-sat-form-wrap"),
    formTitle:  document.getElementById("sch-sat-form-title"),
    form:       document.getElementById("sch-sat-form") as HTMLFormElement | null,
    formCancel: document.getElementById("sch-sat-form-cancel"),
    preset:     document.getElementById("scheduler-sat-preset") as HTMLSelectElement | null,
    name:       document.getElementById("scheduler-sat-name") as HTMLInputElement | null,
    norad:      document.getElementById("scheduler-sat-norad") as HTMLInputElement | null,
    bookmark:   document.getElementById("scheduler-sat-bookmark") as HTMLSelectElement | null,
    minEl:      document.getElementById("scheduler-sat-min-el") as HTMLInputElement | null,
    priority:   document.getElementById("scheduler-sat-priority") as HTMLInputElement | null,
    centerHz:   document.getElementById("scheduler-sat-center-hz") as HTMLInputElement | null,
  };

  // ── Local state ───────────────────────────────────────────────────
  let editIdx: number | null = null;
  let eventsWired = false;

  // ── Scheduler bridge ──────────────────────────────────────────────
  // These accessors use the shared typed scheduler service when available.
  function getBridge(): SchedulerService | null {
    return satSchedulerWindow.trx?.modules?.scheduler ?? null;
  }

  function getConfig(): SchedulerConfig | null {
    const b = getBridge();
    return b?.getConfig() ?? null;
  }

  function getStatus(): SatelliteSchedulerStatus | null {
    const b = getBridge();
    return b?.getStatus() ?? null;
  }

  function getBookmarks(): SatelliteBookmark[] {
    const b = getBridge();
    return b?.getBookmarks() ?? [];
  }

  function markDirty() {
    getBridge()?.markDirty();
  }

  function bmName(id: string): string {
    const bm = getBookmarks().find(function (b) { return b.id === id; });
    return bm ? bm.name : id;
  }

  function escHtml(s: string): string {
    return s
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  function formatFreq(hz: number): string {
    if (hz >= 1e6) return (hz / 1e6).toFixed(3) + " MHz";
    if (hz >= 1e3) return (hz / 1e3).toFixed(1) + " kHz";
    return `${String(hz)} Hz`;
  }

  // ── Satellite config helpers ──────────────────────────────────────
  function getSatelliteEntries(): SatelliteScheduleEntry[] {
    const config = getConfig();
    return (config && config.satellites && Array.isArray(config.satellites.entries))
      ? config.satellites.entries
      : [];
  }

  function ensureSatelliteConfig(): SatelliteScheduleConfig {
    const config = getConfig();
    if (!config) return { enabled: false, pretune_secs: 60, entries: [] };
    if (!config.satellites) config.satellites = { enabled: false, pretune_secs: 60, entries: [] };
    return config.satellites;
  }

  function collectSatelliteConfig(): SatelliteScheduleConfig {
    const enabled = dom.enabled ? dom.enabled.checked : false;
    const pretune = dom.pretune ? parseInt(dom.pretune.value, 10) : 60;
    return {
      enabled: enabled,
      pretune_secs: isNaN(pretune) || pretune < 0 ? 60 : pretune,
      entries: getSatelliteEntries(),
    };
  }

  // ── Render: section ───────────────────────────────────────────────
  function renderSection() {
    const config = getConfig();
    const satCfg = config?.satellites;
    const enabled = satCfg?.enabled ?? false;

    if (dom.enabled) dom.enabled.checked = enabled;
    if (dom.pretune) dom.pretune.value = String(satCfg?.pretune_secs ?? 60);
    if (dom.body) dom.body.style.display = enabled ? "" : "none";

    renderEntries();
    renderPassStatus();
  }

  // ── Render: entries table ─────────────────────────────────────────
  function renderEntries() {
    if (!dom.tbody) return;
    const entries = getSatelliteEntries();
    const frag = document.createDocumentFragment();

    entries.forEach(function (entry, idx) {
      const tr = document.createElement("tr");

      const tdSat = document.createElement("td");
      tdSat.textContent = entry.satellite || "";
      tr.appendChild(tdSat);

      const tdNorad = document.createElement("td");
      tdNorad.textContent = String(entry.norad_id || "");
      tr.appendChild(tdNorad);

      const tdBm = document.createElement("td");
      tdBm.textContent = bmName(entry.bookmark_id);
      tr.appendChild(tdBm);

      const tdEl = document.createElement("td");
      tdEl.textContent = `${String(entry.min_elevation_deg)}\u00B0`;
      tr.appendChild(tdEl);

      const tdPrio = document.createElement("td");
      tdPrio.textContent = String(entry.priority || 0);
      tr.appendChild(tdPrio);

      const tdActions = document.createElement("td");

      const editBtn = document.createElement("button");
      editBtn.className = "sch-write";
      editBtn.type = "button";
      editBtn.textContent = "Edit";
      editBtn.addEventListener("click", function () {
        openForm(entry, idx);
      });
      tdActions.appendChild(editBtn);

      const removeBtn = document.createElement("button");
      removeBtn.className = "sch-write";
      removeBtn.type = "button";
      removeBtn.textContent = "Remove";
      removeBtn.addEventListener("click", function () {
        removeEntry(idx);
      });
      tdActions.appendChild(removeBtn);

      tr.appendChild(tdActions);
      frag.appendChild(tr);
    });

    dom.tbody.replaceChildren(frag);
  }

  // ── Render: pass status ───────────────────────────────────────────
  function renderPassStatus() {
    if (!dom.passStatus) return;
    const entries = getSatelliteEntries();
    if (entries.length === 0) {
      dom.passStatus.innerHTML = "";
      return;
    }
    const status = getStatus();
    if (status && status.active_satellite) {
      dom.passStatus.innerHTML =
        '<span class="sch-sat-active-badge">PASS ACTIVE: ' +
        escHtml(status.active_satellite) +
        '</span>';
    } else {
      dom.passStatus.innerHTML =
        '<span style="color:var(--text-muted);font-size:0.8rem;">No satellite pass active. Predictions available in the SAT tab.</span>';
    }
  }

  // ── Render: bookmark dropdown ─────────────────────────────────────
  function renderBookmarkSelect(selectedId: string | null): void {
    const bookmarkSelect = dom.bookmark;
    if (!bookmarkSelect) return;
    bookmarkSelect.innerHTML = '<option value="">— none —</option>';
    getBookmarks().forEach(function (bm) {
      const opt = document.createElement("option");
      opt.value = bm.id;
      opt.textContent = bm.name + " (" + formatFreq(bm.freq_hz) + " " + bm.mode + ")";
      if (bm.id === selectedId) opt.selected = true;
      bookmarkSelect.appendChild(opt);
    });
  }

  // ── Entry management ──────────────────────────────────────────────
  function removeEntry(idx: number): void {
    const sat = ensureSatelliteConfig();
    sat.entries.splice(idx, 1);
    renderEntries();
    markDirty();
  }

  // ── Form: open ────────────────────────────────────────────────────
  function openForm(entry: SatelliteScheduleEntry | null, idx: number | null): void {
    editIdx = (idx != null) ? idx : null;

    if (dom.formTitle) dom.formTitle.textContent = entry ? "Edit Satellite" : "Add Satellite";
    if (dom.preset)   dom.preset.value = "";
    if (dom.name)     dom.name.value = entry ? (entry.satellite || "") : "";
    if (dom.norad)    dom.norad.value = entry ? String(entry.norad_id || "") : "";
    if (dom.minEl)    dom.minEl.value = String(entry?.min_elevation_deg ?? 5);
    if (dom.priority) dom.priority.value = String(entry?.priority ?? 0);
    if (dom.centerHz) dom.centerHz.value = entry?.center_hz ? String(entry.center_hz) : "";

    renderBookmarkSelect(entry ? entry.bookmark_id : null);

    if (dom.formWrap) {
      dom.formWrap.style.display = "flex";
      if (dom.name) dom.name.focus();
    }
  }

  // ── Form: close ───────────────────────────────────────────────────
  function closeForm() {
    if (dom.formWrap) dom.formWrap.style.display = "none";
    editIdx = null;
  }

  // ── Form: submit ──────────────────────────────────────────────────
  function onFormSubmit(e: SubmitEvent): void {
    e.preventDefault();

    const satellite = dom.name ? dom.name.value.trim() : "";
    const noradId = dom.norad ? parseInt(dom.norad.value, 10) : NaN;
    const bmId = dom.bookmark ? dom.bookmark.value : "";

    if (!satellite) { satSchedulerWindow.trxUi?.notify("Enter a satellite name.", { kind: "error" }); dom.name?.focus(); return; }
    if (isNaN(noradId) || noradId <= 0) { satSchedulerWindow.trxUi?.notify("Enter a valid NORAD catalog number.", { kind: "error" }); dom.norad?.focus(); return; }
    if (!bmId) { satSchedulerWindow.trxUi?.notify("Select a bookmark.", { kind: "error" }); dom.bookmark?.focus(); return; }

    const minEl = dom.minEl ? parseFloat(dom.minEl.value) : 5;
    const prio = dom.priority ? parseInt(dom.priority.value, 10) : 0;
    const centerHzRaw = dom.centerHz ? parseInt(dom.centerHz.value, 10) : NaN;

    const sat = ensureSatelliteConfig();

    const existing = editIdx !== null ? sat.entries[editIdx] : undefined;
    const entryData: SatelliteScheduleEntry = {
      id: existing?.id ?? `sat_${Date.now().toString(36)}`,
      satellite: satellite,
      norad_id: noradId,
      bookmark_id: bmId,
      min_elevation_deg: isNaN(minEl) ? 5 : minEl,
      priority: isNaN(prio) ? 0 : prio,
      center_hz: !isNaN(centerHzRaw) && centerHzRaw > 0 ? centerHzRaw : null,
      bookmark_ids: [],
    };

    if (editIdx !== null) {
      sat.entries[editIdx] = entryData;
    } else {
      sat.entries.push(entryData);
    }

    closeForm();
    renderEntries();
    markDirty();
  }

  // ── Preset change handler ─────────────────────────────────────────
  function onPresetChange() {
    if (!dom.preset || !dom.preset.value) return;
    const parts = dom.preset.value.split("|");
    if (dom.name)  dom.name.value = parts[0] || "";
    if (dom.norad) dom.norad.value = parts[1] || "";
  }

  // ── Wire all events ───────────────────────────────────────────────
  function wireEvents() {
    if (eventsWired) return;
    eventsWired = true;
    if (dom.enabled) {
      const enabledInput = dom.enabled;
      dom.enabled.addEventListener("change", function () {
        if (dom.body) dom.body.style.display = enabledInput.checked ? "" : "none";
        markDirty();
      });
    }
    if (dom.pretune) {
      dom.pretune.addEventListener("input", function () {
        markDirty();
      });
    }
    if (dom.addBtn)     dom.addBtn.addEventListener("click", function () { openForm(null, null); });
    if (dom.form)       dom.form.addEventListener("submit", onFormSubmit);
    if (dom.formCancel) dom.formCancel.addEventListener("click", closeForm);
    if (dom.preset)     dom.preset.addEventListener("change", onPresetChange);
  }

  // ── Public API ────────────────────────────────────────────────────
  satSchedulerWindow.satScheduler = {
    wireEvents:              wireEvents,
    renderSection:           renderSection,
    renderPassStatus:        renderPassStatus,
    collectSatelliteConfig:  collectSatelliteConfig,
  };
  if (getBridge()) {
    wireEvents();
    renderSection();
  }
})();
