/*
 * Wires floorplan3d.js to identity's GET /floorplan/presence.
 *
 * One request gives the plan AND who is in it, so there is no second call and no window
 * where the rooms are drawn but the people are missing.
 */
"use strict";

const params = new URLSearchParams(location.search);
const API = (params.get("api") || "").replace(/\/$/, "");
const TOKEN = params.get("token") || "";
const POLL_MS = Number(params.get("poll") || 15000);

const $ = (id) => document.getElementById(id);

if (!API || !TOKEN) {
  $("error").hidden = false;
  $("error").textContent = "Not configured — needs ?api=&token= in the URL.";
  throw new Error("floorplan: missing ?api=/&token=");
}

const plan = new Floorplan3D($("plan"), {
  // identity serves the picture; this builds the URL rather than the SDK knowing about
  // any particular service.
  photoUrl: (personId) => `${API}/people/${personId}/photo?token=${encodeURIComponent(TOKEN)}`,
});

let levels = [];
let activeLevelId = params.get("level") ? Number(params.get("level")) : null;

function load() {
  fetch(`${API}/floorplan/presence`, { headers: { Authorization: `Bearer ${TOKEN}` } })
    .then((res) => {
      if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
      return res.json();
    })
    .then((data) => {
      $("error").hidden = true;
      levels = data.levels || [];
      if (activeLevelId === null && levels.length) activeLevelId = levels[0].id;
      renderLevelButtons();

      const level = levels.find((l) => l.id === activeLevelId) || levels[0] || null;
      $("level-name").textContent = level ? level.name : "No levels drawn yet";
      plan.setLevel(level, data.unplaced || []);

      // The honest count, in the same sentence: placed people and the ones the system
      // cannot locate. A view that silently omits the second number implies it knows
      // where everybody is.
      const placed = (level ? level.rooms || [] : []).reduce(
        (n, room) => n + (room.occupants || []).length, 0
      );
      const unplaced = (data.unplaced || []).length;
      const rooms = level ? level.rooms || [] : [];
      const exact = rooms.reduce(
        (n, room) => n + (room.occupants || []).filter((p) => p.position).length, 0
      );
      const anonymous = rooms.reduce((n, room) => n + (room.targets || []).length, 0);

      // Every number the view actually knows, said out loud. A summary that reported
      // only "3 placed" would imply the picture is complete when two of the dots are
      // unnamed blobs and one person is somewhere unknown.
      const parts = [`${placed} placed`];
      if (exact) parts.push(`${exact} exact`);
      if (anonymous) parts.push(`${anonymous} unidentified`);
      if (unplaced) parts.push(`${unplaced} home but not locatable`);
      $("summary").textContent = parts.join(" · ");
    })
    .catch((err) => {
      $("error").hidden = false;
      $("error").textContent = `identity: ${err.message}`;
    })
    .finally(() => setTimeout(load, POLL_MS));
}

function renderLevelButtons() {
  if (levels.length < 2) {
    $("levels").innerHTML = "";
    return;
  }
  $("levels").innerHTML = levels
    .map(
      (l) =>
        `<button data-id="${l.id}" class="${l.id === activeLevelId ? "active" : ""}">${escapeHtml(
          l.name
        )}</button>`
    )
    .join("");
  $("levels")
    .querySelectorAll("button")
    .forEach((btn) =>
      btn.addEventListener("click", () => {
        activeLevelId = Number(btn.dataset.id);
        load();
      })
    );
}

function escapeHtml(s) {
  return String(s ?? "").replace(/[&<>"']/g, (c) =>
    ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c])
  );
}

load();
