(() => {
  "use strict";

  const colors = ["#2563eb", "#0f9f6e", "#7a5af8", "#f79009", "#06aed5", "#e0528d", "#64748b", "#84cc16"];
  const BUSINESS_TIME_ZONE = "Asia/Bangkok";
  const I18N = window.ARRI18n;
  const $ = (selector) => document.querySelector(selector);
  const BI_POLL_INTERVAL = 5000;
  let csrf = "";
  let lastData = null;
  let dataLoading = false;
  let biPollTimer = null;
  let biPollLoading = false;

  function escapeHtml(value) {
    return String(value ?? "").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#039;");
  }

  function monthNow() {
    const parts = Object.fromEntries(new Intl.DateTimeFormat("en-CA", {
      timeZone: BUSINESS_TIME_ZONE,
      year: "numeric",
      month: "2-digit",
    }).formatToParts(new Date()).map((part) => [part.type, part.value]));
    return `${parts.year}-${parts.month}`;
  }

  function integer(value) {
    return I18N?.formatInteger(value) || new Intl.NumberFormat("zh-CN", { maximumFractionDigits: 0 }).format(Number(value || 0));
  }

  function money(value, compact = true) {
    if (I18N) return I18N.formatMoney(value, compact);
    const amount = Number(value || 0);
    return new Intl.NumberFormat("zh-CN", { style: "currency", currency: "CNY", maximumFractionDigits: 0 }).format(amount);
  }

  function redirectToLogin() {
    window.location.replace("/login?next=%2Fh5");
  }

  async function api(path, options = {}) {
    const allowUnauthorized = Boolean(options.allowUnauthorized);
    const requestOptions = { ...options };
    delete requestOptions.allowUnauthorized;
    const headers = new Headers(options.headers || {});
    if (options.method && options.method !== "GET") headers.set("X-ARR-CSRF", csrf);
    const response = await fetch(path, { ...requestOptions, headers, credentials: "same-origin" });
    if (response.status === 401) {
      if (allowUnauthorized) return null;
      redirectToLogin();
      throw new Error(I18N?.errorMessage("SESSION_INVALID", "登录状态已失效") || "登录状态已失效");
    }
    let payload;
    try {
      payload = await response.json();
    } catch (_) {
      throw new Error(I18N?.t("error.unrecognized_response") || "服务返回了无法识别的结果");
    }
    if (!response.ok || !payload.ok) {
      const error = payload?.error || {};
      throw new Error(I18N?.errorMessage(error.code, error.message) || error.message || I18N?.t("error.database_read_unavailable") || "数据读取失败");
    }
    return payload.data;
  }

  function notify(message) {
    const node = $("#h5-message");
    node.textContent = I18N?.text(message) || message;
    node.classList.add("visible");
    window.setTimeout(() => node.classList.remove("visible"), 3000);
  }

  function reset(message) {
    ["#h5-rooms", "#h5-revenue", "#h5-nights", "#h5-companies", "#h5-donut-total"].forEach((id) => { $(id).textContent = "—"; });
    const copy = I18N?.text(message) || message;
    $("#h5-ranking").innerHTML = `<p class="empty">${escapeHtml(copy)}</p>`;
    $("#h5-matrix").innerHTML = `<p class="empty">${escapeHtml(copy)}</p>`;
    $("#h5-legend").innerHTML = "";
    $("#h5-donut").style.background = "#d8e0ec";
    $("#h5-data-range").textContent = I18N?.t("bi.data_range", { start: "—", end: "—" }) || "数据范围：—";
  }

  function dataRange(data) {
    const start = data.min_arrival_date ? (I18N?.formatDate(data.min_arrival_date) || data.min_arrival_date) : "—";
    const end = data.max_arrival_date ? (I18N?.formatDate(data.max_arrival_date) || data.max_arrival_date) : "—";
    return I18N?.t("bi.data_range", { start, end }) || `数据范围：${start} – ${end}`;
  }

  function renderSales(channels) {
    const sorted = [...channels].sort((a, b) => Number(b.totals.total_price) - Number(a.totals.total_price));
    const total = sorted.reduce((sum, item) => sum + Number(item.totals.total_price || 0), 0);
    const maximum = Math.max(1, ...sorted.map((item) => Number(item.totals.total_price || 0)));
    let cursor = 0;
    const stops = sorted.map((item, index) => {
      const start = cursor;
      cursor += total ? Number(item.totals.total_price || 0) / total * 100 : 0;
      return `${colors[index % colors.length]} ${start.toFixed(3)}% ${cursor.toFixed(3)}%`;
    });
    $("#h5-donut").style.background = total ? `conic-gradient(${stops.join(",")})` : "#d8e0ec";
    $("#h5-donut-total").textContent = money(total);
    $("#h5-legend").innerHTML = sorted.map((item, index) => `
      <span class="mobile-legend-item"><i data-color="${colors[index % colors.length]}"></i><span>${escapeHtml(item.worksheet)}</span><b>${total ? (Number(item.totals.total_price || 0) / total * 100).toFixed(1) : "0.0"}%</b></span>`).join("");
    [...document.querySelectorAll("#h5-legend .mobile-legend-item i")].forEach((marker) => { marker.style.backgroundColor = marker.dataset.color; });
    $("#h5-ranking").innerHTML = sorted.length ? sorted.map((item) => `
      <div class="mobile-rank"><span title="${escapeHtml(item.worksheet)}">${escapeHtml(item.worksheet)}</span><span class="track"><i data-width="${Number(item.totals.total_price || 0) / maximum * 100}"></i></span><b>${money(item.totals.total_price)}</b></div>`).join("") : `<p class="empty">${escapeHtml(I18N?.t("bi.empty_sales") || "暂无销售数据")}</p>`;
    [...document.querySelectorAll("#h5-ranking .track i")].forEach((bar) => { bar.style.width = `${Number(bar.dataset.width || 0)}%`; });
  }

  function renderMatrix(data) {
    const rooms = data.overall.room_types.map((item) => item.room_type);
    if (!rooms.length || !data.channels.length) {
      $("#h5-matrix").innerHTML = `<p class="empty">${escapeHtml(I18N?.t("bi.empty") || "暂无渠道与房型数据")}</p>`;
      return;
    }
    const rows = data.channels.map((channel) => {
      const values = new Map(channel.room_types.map((item) => [item.room_type, item.rooms_sold]));
      return `<tr><td><b>${escapeHtml(channel.worksheet)}</b></td>${rooms.map((room) => `<td>${integer(values.get(room) || 0)}</td>`).join("")}<td class="total">${integer(channel.totals.rooms_sold)}</td></tr>`;
    }).join("");
    const totals = new Map(data.overall.room_types.map((item) => [item.room_type, item.rooms_sold]));
    const channelLabel = I18N?.t("bi.channel") || "渠道";
    const totalLabel = I18N?.t("common.total") || "合计";
    $("#h5-matrix").innerHTML = `<table><thead><tr><th>${escapeHtml(channelLabel)}</th>${rooms.map((room) => `<th>${escapeHtml(room)}</th>`).join("")}<th>${escapeHtml(totalLabel)}</th></tr></thead><tbody>${rows}<tr><td class="total">${escapeHtml(totalLabel)}</td>${rooms.map((room) => `<td class="total">${integer(totals.get(room) || 0)}</td>`).join("")}<td class="total">${integer(data.overall.totals.rooms_sold)}</td></tr></tbody></table>`;
  }

  function render(data) {
    lastData = data;
    const totals = data.overall.totals;
    $("#h5-rooms").textContent = integer(totals.rooms_sold);
    $("#h5-revenue").textContent = money(totals.total_price);
    $("#h5-nights").textContent = integer(totals.room_nights);
    $("#h5-companies").textContent = integer(totals.channel_count);
    $("#h5-data-range").textContent = dataRange(data);
    renderSales(data.channels);
    renderMatrix(data);
  }

  function populateMonths(months) {
    const select = $("#h5-month");
    const current = select.value;
    select.innerHTML = months.length
      ? months.map((item) => `<option value="${escapeHtml(item.month_key)}">${escapeHtml(item.month_key)}</option>`).join("")
      : `<option value="${monthNow()}">${monthNow()}</option>`;
    if (months.some((item) => item.month_key === current)) select.value = current;
  }

  async function load(showErrors = true, preserveOnError = false) {
    if (dataLoading) return;
    dataLoading = true;
    const month = $("#h5-month").value || monthNow();
    try {
      render(await api(`/api/public/h5/analytics?month=${encodeURIComponent(month)}`));
    } catch (error) {
      if (!preserveOnError) reset(I18N?.t("bi.empty") || "该月份暂无可用看板数据");
      if (showErrors) notify(error.message);
    } finally {
      dataLoading = false;
    }
  }

  function clearBiPoll() {
    window.clearTimeout(biPollTimer);
    biPollTimer = null;
  }

  function scheduleBiPoll(delay = BI_POLL_INTERVAL) {
    clearBiPoll();
    if (document.hidden) return;
    biPollTimer = window.setTimeout(checkBiFreshness, delay);
  }

  async function checkBiFreshness() {
    if (biPollLoading || dataLoading || document.hidden) {
      scheduleBiPoll();
      return;
    }
    biPollLoading = true;
    try {
      const months = await api("/api/public/h5/months");
      populateMonths(months);
      const month = $("#h5-month").value || monthNow();
      const metadata = months.find((item) => item.month_key === month);
      const changed = !lastData
        || lastData.month_key !== month
        || Boolean(metadata && metadata.updated_at !== lastData.updated_at);
      if (changed) await load(false, Boolean(lastData));
    } catch (_) {
      // Keep the last good H5 snapshot during a transient background failure.
    } finally {
      biPollLoading = false;
      scheduleBiPoll();
    }
  }

  document.addEventListener("arr:locale-change", () => {
    if (lastData) render(lastData);
    I18N?.translateDom();
  });

  async function boot() {
    const connection = $("#h5-connection");
    try {
      const session = await api("/api/session", { allowUnauthorized: true });
      csrf = session?.csrf_token || "";
      const logout = $("#h5-logout");
      if (session?.username) {
        logout.hidden = false;
        logout.removeAttribute("aria-disabled");
        logout.classList.remove("is-busy");
        logout.title = `${session.username} · ${I18N?.t("auth.logout") || "退出登录"}`;
        logout.addEventListener("click", async (event) => {
          event.preventDefault();
          if (logout.getAttribute("aria-disabled") === "true") return;
          logout.setAttribute("aria-disabled", "true");
          logout.classList.add("is-busy");
          try {
            await api("/api/logout", { method: "POST" });
            window.location.replace("/login");
          } catch (error) {
            notify(error.message || I18N?.t("auth.logout_failed") || "退出登录失败，请重试");
            logout.removeAttribute("aria-disabled");
            logout.classList.remove("is-busy");
          }
        });
      }
    } catch (_) {
      // Session lookup is optional for the public read-only dashboard.
    }
    try {
      const healthResponse = await fetch("/healthz", {
        credentials: "same-origin",
        cache: "no-store",
      });
      const databaseReady = healthResponse.ok;
      connection.classList.add(databaseReady ? "ready" : "error");
      connection.lastChild.textContent = databaseReady
        ? ""
        : ` ${I18N?.t("status.service_disconnected") || "数据服务未连接"}`;
      connection.setAttribute(
        "aria-label",
        databaseReady
          ? (I18N?.t("status.service_ready") || "服务正常")
          : (I18N?.t("status.service_disconnected") || "数据服务未连接"),
      );
    } catch (_) {
      connection.classList.add("error");
      connection.lastChild.textContent = ` ${I18N?.t("status.service_disconnected") || "数据服务未连接"}`;
      connection.setAttribute("aria-label", I18N?.t("status.service_disconnected") || "数据服务未连接");
    }
    let months = [];
    try { months = await api("/api/public/h5/months"); } catch (_) { /* handled by load */ }
    populateMonths(months);
    const select = $("#h5-month");
    select.addEventListener("change", () => load(true));
    await load();
    scheduleBiPoll(250);
  }

  document.addEventListener("visibilitychange", () => {
    if (document.hidden) clearBiPoll();
    else checkBiFreshness();
  });

  boot();
})();
