// Litigation Builder — share-with-team UI (m/paliad#153 PRD §2.5, B5).
//
// "Teilen" opens a modal with an HLC user picker. Picking a colleague +
// "Schreibgeschützt teilen" POSTs a paliad.scenario_shares row; the owner
// stays sole editor. Existing shares are listed with a revoke affordance.
// The sharee sees the scenario in their "Geteilt mit mir" bucket (read-
// only) — that side is handled by builder.ts.

import { t } from "./i18n";

export interface ShareUser {
  id: string;
  email: string;
  display_name?: string;
  office?: string;
}

export interface BuilderShareRow {
  id: string;
  scenario_id: string;
  shared_with_user_id: string;
  created_by: string;
  created_at: string;
}

interface ShareModalOpts {
  scenarioId: string;
  ownerId?: string;
  currentShares: BuilderShareRow[];
  // Called after a successful add/revoke with the fresh share list so the
  // caller can update state.active.shares + re-render side panel buckets.
  onChanged: (shares: BuilderShareRow[]) => void;
}

let allUsers: ShareUser[] | null = null;

async function fetchUsers(): Promise<ShareUser[]> {
  if (allUsers) return allUsers;
  try {
    const resp = await fetch("/api/users");
    if (!resp.ok) return [];
    const data = (await resp.json()) as ShareUser[];
    allUsers = Array.isArray(data) ? data : [];
    return allUsers;
  } catch {
    return [];
  }
}

function userLabel(u: ShareUser): string {
  const name = (u.display_name || "").trim();
  if (name) return u.office ? `${name} · ${u.office}` : name;
  return u.email;
}

export async function openShareModal(opts: ShareModalOpts): Promise<void> {
  const users = await fetchUsers();
  let shares = [...opts.currentShares];

  const backdrop = document.createElement("div");
  backdrop.className = "builder-modal-backdrop";
  backdrop.innerHTML = `
    <div class="builder-modal builder-share-modal" role="dialog" aria-modal="true"
         aria-label="${escAttr(t("builder.share.title"))}">
      <header class="builder-modal-header">
        <h2 class="builder-modal-title">${escHtml(t("builder.share.title"))}</h2>
        <button type="button" class="builder-modal-close" aria-label="${escAttr(t("builder.share.close"))}">×</button>
      </header>
      <p class="builder-modal-subtitle">${escHtml(t("builder.share.subtitle"))}</p>
      <div class="builder-share-pickerbox">
        <input type="search" class="builder-share-search" autocomplete="off" spellcheck="false"
               placeholder="${escAttr(t("builder.share.search.placeholder"))}" />
        <ul class="builder-share-results" aria-label="${escAttr(t("builder.share.title"))}"></ul>
      </div>
      <div class="builder-share-current">
        <h3 class="builder-share-current-title">${escHtml(t("builder.share.current.title"))}</h3>
        <ul class="builder-share-current-list"></ul>
      </div>
    </div>`;

  const close = () => {
    document.removeEventListener("keydown", onEsc, true);
    backdrop.remove();
  };
  const onEsc = (e: KeyboardEvent) => {
    if (e.key === "Escape") close();
  };
  backdrop.addEventListener("click", (e) => {
    if (e.target === backdrop) close();
  });
  backdrop.querySelector(".builder-modal-close")?.addEventListener("click", close);
  document.addEventListener("keydown", onEsc, true);

  const searchEl = backdrop.querySelector(".builder-share-search") as HTMLInputElement;
  const resultsEl = backdrop.querySelector(".builder-share-results") as HTMLElement;
  const currentEl = backdrop.querySelector(".builder-share-current-list") as HTMLElement;

  function renderCurrent(): void {
    if (shares.length === 0) {
      currentEl.innerHTML = `<li class="builder-share-current-empty">${escHtml(t("builder.share.current.empty"))}</li>`;
      return;
    }
    currentEl.innerHTML = shares.map((sh) => {
      const u = users.find((x) => x.id === sh.shared_with_user_id);
      const label = u ? userLabel(u) : sh.shared_with_user_id;
      return (
        `<li class="builder-share-current-item" data-share-id="${escAttr(sh.id)}">` +
        `<span class="builder-share-current-name">${escHtml(label)}</span>` +
        `<button type="button" class="builder-share-revoke">${escHtml(t("builder.share.revoke"))}</button>` +
        `</li>`
      );
    }).join("");
    currentEl.querySelectorAll<HTMLElement>(".builder-share-current-item").forEach((li) => {
      const id = li.getAttribute("data-share-id");
      if (!id) return;
      li.querySelector(".builder-share-revoke")?.addEventListener("click", () => {
        void revoke(id);
      });
    });
  }

  function renderResults(): void {
    const q = searchEl.value.trim().toLowerCase();
    const sharedIds = new Set(shares.map((s) => s.shared_with_user_id));
    const matches = users
      .filter((u) => u.id !== opts.ownerId && !sharedIds.has(u.id))
      .filter((u) => {
        if (!q) return true;
        return (
          (u.display_name || "").toLowerCase().includes(q) ||
          u.email.toLowerCase().includes(q) ||
          (u.office || "").toLowerCase().includes(q)
        );
      })
      .slice(0, 12);
    if (matches.length === 0) {
      resultsEl.innerHTML = `<li class="builder-share-result-empty">${escHtml(t("builder.share.no_results"))}</li>`;
      return;
    }
    resultsEl.innerHTML = matches.map((u) => (
      `<li class="builder-share-result" data-user-id="${escAttr(u.id)}">` +
      `<span class="builder-share-result-name">${escHtml(userLabel(u))}</span>` +
      `<button type="button" class="builder-share-add">${escHtml(t("builder.share.button"))}</button>` +
      `</li>`
    )).join("");
    resultsEl.querySelectorAll<HTMLElement>(".builder-share-result").forEach((li) => {
      const uid = li.getAttribute("data-user-id");
      if (!uid) return;
      li.querySelector(".builder-share-add")?.addEventListener("click", () => {
        void add(uid);
      });
    });
  }

  async function add(userId: string): Promise<void> {
    try {
      const resp = await fetch(
        "/api/builder/scenarios/" + encodeURIComponent(opts.scenarioId) + "/shares",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ shared_with_user_id: userId }),
        },
      );
      if (!resp.ok) {
        flashError();
        return;
      }
      const row = (await resp.json()) as BuilderShareRow;
      shares = [...shares.filter((s) => s.id !== row.id), row];
      searchEl.value = "";
      renderResults();
      renderCurrent();
      opts.onChanged(shares);
    } catch {
      flashError();
    }
  }

  async function revoke(shareId: string): Promise<void> {
    try {
      const resp = await fetch(
        "/api/builder/scenarios/" + encodeURIComponent(opts.scenarioId) +
          "/shares/" + encodeURIComponent(shareId),
        { method: "DELETE" },
      );
      if (!resp.ok && resp.status !== 204) {
        flashError();
        return;
      }
      shares = shares.filter((s) => s.id !== shareId);
      renderResults();
      renderCurrent();
      opts.onChanged(shares);
    } catch {
      flashError();
    }
  }

  function flashError(): void {
    const box = backdrop.querySelector(".builder-share-pickerbox") as HTMLElement;
    let err = box.querySelector(".builder-share-error") as HTMLElement | null;
    if (!err) {
      err = document.createElement("p");
      err.className = "builder-share-error";
      box.appendChild(err);
    }
    err.textContent = t("builder.share.error");
  }

  searchEl.addEventListener("input", renderResults);
  renderResults();
  renderCurrent();
  document.body.appendChild(backdrop);
  searchEl.focus();
}

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

function escAttr(s: string): string {
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
}
