(() => {
  const el = (id) => document.getElementById(id);

  const LOCALE_META = {
    vi: { flag: "🇻🇳", labelKey: "topbar.localeVi" },
    en: { flag: "🇺🇸", labelKey: "topbar.localeEn" },
  };

  const t = (key, vars) => window.I18n?.t(key, vars) ?? key;
  const getLocale = () => window.I18n?.getLocale?.() ?? "vi";

  let robotStatus = null;
  let pollTimer = null;
  let eventsBound = false;
  let openPanel = null;
  let joystickActive = false;
  let joystickPointerId = null;
  let joystickRaf = null;
  let lastCmd = { linear: 0, angular: 0 };

  function applyLocale(next) {
    if (window.I18n) window.I18n.setLocale(next);
    if (robotStatus) renderAll(robotStatus);
  }

  function loadLocale() {
    /* locale owned by I18n */
  }

  function canSeeMissions() {
    return window.AuthApp?.canAccessPage?.("missions");
  }

  function canControl() {
    return window.AuthApp?.canWrite?.("missions");
  }

  async function apiJson(path, opts = {}) {
    const res = await fetch(path, {
      credentials: "include",
      headers: { "Content-Type": "application/json", ...(opts.headers || {}) },
      ...opts,
    });
    const text = await res.text();
    let data = null;
    try {
      data = text ? JSON.parse(text) : null;
    } catch {
      data = null;
    }
    if (!res.ok) throw new Error((data && data.error) || text || res.statusText);
    return data;
  }

  function closePanels() {
    document.querySelectorAll(".mirPanel").forEach((p) => {
      p.hidden = true;
    });
    document.querySelectorAll(".mirSegment[aria-haspopup='true']").forEach((btn) => {
      btn.setAttribute("aria-expanded", "false");
    });
    openPanel = null;
  }

  function togglePanel(btn, panel) {
    if (!btn || !panel) return;
    const isOpen = btn.getAttribute("aria-expanded") === "true";
    closePanels();
    if (!isOpen) {
      panel.hidden = false;
      btn.setAttribute("aria-expanded", "true");
      openPanel = panel;
    }
  }

  function missionStripMessage(status) {
    const pending = Number(status.queue_pending) || 0;
    const runnerState = status.runner?.state || "idle";
    const msg = status.message || "";
    if (runnerState === "running" || runnerState === "paused") {
      if (msg && msg !== t("topbar.waiting")) return msg;
      const name = status.runner?.current_action;
      if (name) return String(name);
    }
    if (pending === 0 && runnerState === "idle") return t("topbar.noMissionsQueue");
    if (msg && msg !== t("topbar.waiting")) return msg;
    return t("topbar.waiting");
  }

  function renderControl(status) {
    const motion = status.motion || "paused";
    const running = motion === "running";
    const runnerState = status.runner?.state || "idle";
    const isError = status.health === "error" || runnerState === "error";

    const pauseIcon = el("mirControlIconPause");
    const playIcon = el("mirControlIconPlay");
    const pillEl = el("mirControlPill");
    const msgEl = el("mirMissionMsg");
    const btnEl = el("mirSegControl");
    const stripEl = el("mirMissionStrip");

    if (pauseIcon && playIcon) {
      pauseIcon.hidden = !running;
      playIcon.hidden = running;
    }
    if (pillEl) {
      pillEl.textContent = isError ? t("topbar.error") : running ? t("topbar.running") : t("topbar.paused");
      pillEl.classList.toggle("is-running", running && !isError);
      pillEl.classList.toggle("is-paused", !running && !isError);
      pillEl.classList.toggle("is-error", isError);
    }
    if (msgEl) msgEl.textContent = missionStripMessage(status);
    if (stripEl) stripEl.classList.toggle("is-error", isError);

    if (btnEl) {
      btnEl.disabled = !canControl() || status.health === "error";
      btnEl.title = running ? t("topbar.pauseHint") : t("topbar.startHint");
      btnEl.classList.toggle("is-readonly", !canControl());
    }
  }

  function renderStatus(status) {
    const health = status.health || "ok";
    const runnerState = status.runner?.state || "idle";
    const isError = health === "error" || runnerState === "error";
    const labelEl = el("mirStatusLabel");
    const iconEl = el("mirStatusIcon");
    const bodyEl = el("mirStatusPanelBody");
    const footerEl = el("mirStatusPanelFooter");
    const segEl = el("mirSegStatus");

    if (labelEl) labelEl.textContent = isError ? t("topbar.error") : t("topbar.allOk");
    if (iconEl) {
      iconEl.classList.toggle("is-ok", !isError);
      iconEl.classList.toggle("is-error", isError);
    }
    if (segEl) segEl.classList.toggle("is-error", isError);

    if (!bodyEl) return;
    const err = status.error && typeof status.error === "object" ? status.error : null;
    const runnerErr = runnerState === "error" ? status.runner?.message : "";
    const message = status.message || t("topbar.waiting");

    if (isError && (err || runnerErr)) {
      bodyEl.innerHTML = `
        <div class="mirStatusErrorTitle">${t("topbar.error")}</div>
        ${err?.code != null ? `<div class="mirStatusRow"><span>${t("topbar.code")}:</span> <strong>${err.code}</strong></div>` : ""}
        ${err?.module ? `<div class="mirStatusRow"><span>${t("topbar.module")}:</span> ${err.module}</div>` : ""}
        <div class="mirStatusDesc">${err?.description || runnerErr || message}</div>`;
      if (footerEl) footerEl.hidden = !canControl();
    } else {
      bodyEl.innerHTML = `
        <div class="mirStatusOkTitle">${t("topbar.allOk")}</div>
        <div class="mirStatusDesc">${message}</div>
        ${status.queue_pending > 0 ? `<div class="mirStatusMeta">${t("topbar.queueCount", { n: status.queue_pending })}</div>` : ""}`;
      if (footerEl) footerEl.hidden = true;
    }
  }

  function renderBattery(status) {
    const pct = Math.max(0, Math.min(100, Number(status.battery_percent) || 0));
    const labelEl = el("mirBatteryLabel");
    const levelEl = el("mirBatteryLevel");
    const segEl = el("mirSegBattery");
    if (labelEl) labelEl.textContent = `${pct}%`;
    if (levelEl) levelEl.style.width = `${pct}%`;
    if (segEl) {
      segEl.classList.toggle("is-low", pct < 20);
      segEl.classList.toggle("is-mid", pct >= 20 && pct < 50);
      segEl.classList.toggle("is-charging", !!status.battery_charging);
    }
  }

  function hideJoystickOverlay() {
    const overlay = el("joystickOverlay");
    if (overlay) overlay.hidden = true;
    joystickActive = false;
    const stick = el("joystickStick");
    if (stick) stick.style.transform = "translate(0, 0)";
    lastCmd = { linear: 0, angular: 0 };
  }

  function renderJoystick(status) {
    if (!window.AuthApp?.isReady?.()) {
      hideJoystickOverlay();
      return;
    }
    const seg = el("mirSegJoystick");
    const engaged = !!status.joystick_engaged;
    if (seg) seg.classList.toggle("is-active", engaged);
    const overlay = el("joystickOverlay");
    if (overlay) overlay.hidden = !engaged;
    joystickActive = engaged;
    const speedSel = el("joystickSpeedSelect");
    if (speedSel && status.joystick_speed) speedSel.value = status.joystick_speed;
    if (el("joystickSpeedLabel")) {
      const speed = status.joystick_speed || "fast";
      el("joystickSpeedLabel").textContent = t(`topbar.joystickSpeed.${speed}`);
    }
  }

  function renderAll(status) {
    if (!window.AuthApp?.isReady?.()) {
      hideJoystickOverlay();
      return;
    }
    robotStatus = status;
    if (!canSeeMissions()) {
      el("mirTopbar")?.classList.add("mirTopbar--no-missions");
      return;
    }
    el("mirTopbar")?.classList.remove("mirTopbar--no-missions");
    renderControl(status);
    renderStatus(status);
    renderBattery(status);
    renderJoystick(status);
  }

  async function fetchStatus() {
    if (!window.AuthApp?.isReady() || !canSeeMissions()) return;
    try {
      const data = await apiJson("/api/robot/status");
      renderAll(data);
      window.dispatchEvent(new CustomEvent("lm:robot-status", { detail: data }));
    } catch (e) {
      if (String(e.message || "").includes("not authenticated")) return;
    }
  }

  function startPoll() {
    stopPoll();
    fetchStatus();
    pollTimer = setInterval(fetchStatus, 1500);
    window.MissionsApp?.startQueuePoll?.();
  }

  function stopPoll() {
    if (pollTimer) {
      clearInterval(pollTimer);
      pollTimer = null;
    }
    window.MissionsApp?.stopQueuePoll?.();
  }

  async function toggleRobotMotion() {
    if (!robotStatus || !canControl()) return;
    const running = robotStatus.motion === "running";
    const path = running ? "/api/robot/pause" : "/api/robot/start";
    const data = await apiJson(path, { method: "POST", body: "{}" });
    renderAll(data);
  }

  async function resetError() {
    const data = await apiJson("/api/robot/errors/reset", { method: "POST", body: "{}" });
    renderAll(data);
    closePanels();
  }

  async function engageJoystick(engaged, speed) {
    const payload = { engaged };
    if (speed) payload.speed = speed;
    const data = await apiJson("/api/robot/joystick", {
      method: "POST",
      body: JSON.stringify(payload),
    });
    renderAll(data);
  }

  function sendCmdVel(linear, angular) {
    if (!joystickActive) return;
    if (Math.abs(linear - lastCmd.linear) < 0.02 && Math.abs(angular - lastCmd.angular) < 0.02) return;
    lastCmd = { linear, angular };
    apiJson("/api/robot/cmd_vel", {
      method: "POST",
      body: JSON.stringify({ linear, angular }),
    }).catch(() => {});
  }

  function bindJoystickPad() {
    const pad = el("joystickPad");
    const stick = el("joystickStick");
    if (!pad || !stick) return;

    const center = () => {
      const r = pad.getBoundingClientRect();
      return { x: r.left + r.width / 2, y: r.top + r.height / 2, radius: r.width / 2 - 24 };
    };

    const moveStick = (clientX, clientY) => {
      const c = center();
      let dx = clientX - c.x;
      let dy = clientY - c.y;
      const dist = Math.hypot(dx, dy);
      if (dist > c.radius) {
        dx = (dx / dist) * c.radius;
        dy = (dy / dist) * c.radius;
      }
      stick.style.transform = `translate(${dx}px, ${dy}px)`;
      const linear = -dy / c.radius;
      const angular = dx / c.radius;
      if (joystickRaf) cancelAnimationFrame(joystickRaf);
      joystickRaf = requestAnimationFrame(() => sendCmdVel(linear, angular));
    };

    const resetStick = () => {
      stick.style.transform = "translate(0, 0)";
      sendCmdVel(0, 0);
      lastCmd = { linear: 0, angular: 0 };
    };

    const onDown = (evt) => {
      if (!joystickActive) return;
      joystickPointerId = evt.pointerId;
      pad.setPointerCapture(evt.pointerId);
      moveStick(evt.clientX, evt.clientY);
    };
    const onMove = (evt) => {
      if (evt.pointerId !== joystickPointerId) return;
      moveStick(evt.clientX, evt.clientY);
    };
    const onUp = (evt) => {
      if (evt.pointerId !== joystickPointerId) return;
      joystickPointerId = null;
      resetStick();
    };

    pad.addEventListener("pointerdown", onDown);
    pad.addEventListener("pointermove", onMove);
    pad.addEventListener("pointerup", onUp);
    pad.addEventListener("pointercancel", onUp);
  }

  function bindEvents() {
    if (eventsBound) return;
    eventsBound = true;

    el("mirSegControl")?.addEventListener("click", () => {
      toggleRobotMotion().catch((e) => alert(e.message));
    });

    el("mirSegStatus")?.addEventListener("click", (evt) => {
      evt.stopPropagation();
      togglePanel(el("mirSegStatus"), el("mirStatusPanel"));
    });

    el("mirSegLocale")?.addEventListener("click", (evt) => {
      evt.stopPropagation();
      togglePanel(el("mirSegLocale"), el("mirLocalePanel"));
    });

    el("mirUserBtn")?.addEventListener("click", (evt) => {
      evt.stopPropagation();
      togglePanel(el("mirUserBtn"), el("mirUserPanel"));
    });

    el("mirErrorResetBtn")?.addEventListener("click", () => {
      resetError().catch((e) => alert(e.message));
    });

    document.querySelectorAll(".mirLocaleOption").forEach((btn) => {
      btn.addEventListener("click", (evt) => {
        evt.stopPropagation();
        applyLocale(btn.dataset.locale || "vi");
        closePanels();
      });
    });

    el("mirSegJoystick")?.addEventListener("click", async () => {
      if (!canControl()) {
        alert(t("topbar.noControlPermission"));
        return;
      }
      try {
        if (robotStatus?.joystick_engaged) await engageJoystick(false);
        else await engageJoystick(true, el("joystickSpeedSelect")?.value || "fast");
      } catch (e) {
        alert(e.message);
      }
    });

    el("joystickDisengageBtn")?.addEventListener("click", () => {
      engageJoystick(false).catch((e) => alert(e.message));
    });

    el("joystickSpeedSelect")?.addEventListener("change", (evt) => {
      if (robotStatus?.joystick_engaged) {
        engageJoystick(true, evt.target.value).catch(() => {});
      }
    });

    document.addEventListener("click", (evt) => {
      if (evt.target.closest(".mirSegment") || evt.target.closest(".mirPanel")) return;
      closePanels();
    });

    document.addEventListener("keydown", (evt) => {
      if (evt.key === "Escape") {
        closePanels();
        if (robotStatus?.joystick_engaged) engageJoystick(false).catch(() => {});
      }
    });

    bindJoystickPad();
    window.addEventListener("lm:locale-change", () => {
      if (robotStatus) renderAll(robotStatus);
    });
  }

  function start() {
    loadLocale();
    bindEvents();
    if (!window.AuthApp?.isReady()) return;
    startPoll();
  }

  function stop() {
    stopPoll();
    closePanels();
    hideJoystickOverlay();
    if (window.AuthApp?.isReady?.()) {
      engageJoystick(false).catch(() => {});
    }
  }

  async function disengageJoystick() {
    hideJoystickOverlay();
    if (!window.AuthApp?.isReady?.()) return;
    try {
      await engageJoystick(false);
    } catch {
      /* session may already be gone */
    }
  }

  window.TopbarApp = {
    t,
    getLocale,
    applyLocale,
    refresh: fetchStatus,
    getRobotStatus: () => robotStatus,
    hideJoystickOverlay,
    disengageJoystick,
    updateUserMenu(user) {
      const role = (user?.group_name || "USER").toUpperCase();
      if (el("mirUserLabel")) el("mirUserLabel").textContent = role;
      if (el("mirUserPanelRole")) el("mirUserPanelRole").textContent = role;
      if (el("mirUserPanelName")) el("mirUserPanelName").textContent = user?.display_name || user?.username || "—";
      if (el("mirProfileDisplayName")) el("mirProfileDisplayName").value = user?.display_name || user?.username || "";
    },
  };

  if (window.AuthApp?.isReady()) start();
  else window.addEventListener("lm:auth-ready", () => start(), { once: true });
  window.addEventListener("lm:auth-logout", () => stop());
  hideJoystickOverlay();
})();
