import { initI18n, onLangChange, t, tDyn } from "./i18n";
import { initSidebar } from "./sidebar";

interface User {
  id: string;
  email: string;
  display_name: string;
  office: string;
  additional_offices?: string[];
  job_title: string | null;
  // t-paliad-148: structured firm-tier (partner/of_counsel/associate/
  // senior_pa/pa/paralegal). NULL = external. Editable via the
  // admin-team Profession column.
  profession?: string | null;
  global_role: string;
  lang: string;
  reminder_morning_time?: string;
  reminder_evening_time?: string;
  reminder_timezone?: string;
  created_at: string;
}

const PROFESSION_VALUES = [
  "partner",
  "of_counsel",
  "associate",
  "senior_pa",
  "pa",
  "paralegal",
];

interface Office {
  key: string;
  label_de: string;
  label_en: string;
}

interface Unonboarded {
  id: string;
  email: string;
  created_at: string;
}

const OFFICE_ORDER = ["munich", "duesseldorf", "hamburg", "amsterdam", "london", "paris", "milan"];
const JOB_TITLE_SUGGESTIONS = [
  "Partner",
  "Associate",
  "PA",
  "Of Counsel",
  "Counsel",
  "Counsel Knowledge Lawyer",
  "Knowledge Lawyer",
  "Referendar/in",
  "Trainee",
  "wiss. Mitarbeiter/in",
  "Sekretariat",
];

let users: User[] = [];
let offices: Office[] = [];
let unonboarded: Unonboarded[] = [];
let activeOffice = "all";
let searchQuery = "";
let editingId: string | null = null;

function esc(s: string): string {
  const d = document.createElement("div");
  d.textContent = s;
  return d.innerHTML;
}

function officeLabel(key: string): string {
  const o = offices.find((x) => x.key === key);
  if (!o) return key;
  return tDyn("office." + key) || (document.documentElement.lang === "en" ? o.label_en : o.label_de);
}

function fmtDate(iso: string): string {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toLocaleDateString();
}

function permissionLabel(globalRole: string): string {
  if (globalRole === "global_admin") return t("admin.team.permission.global_admin") || "Global Admin";
  return t("admin.team.permission.standard") || "Standard";
}

async function loadAll() {
  const [usersResp, officesResp] = await Promise.all([
    fetch("/api/admin/users"),
    fetch("/api/offices"),
  ]);
  if (usersResp.status === 403) {
    showFeedback(t("admin.team.error.forbidden") || "Nur Admins.", true);
    return;
  }
  if (usersResp.ok) users = (await usersResp.json()) as User[];
  if (officesResp.ok) offices = (await officesResp.json()) as Office[];
  buildOfficeFilters();
  render();
}

async function loadUnonboarded() {
  const resp = await fetch("/api/admin/users/unonboarded");
  if (!resp.ok) {
    unonboarded = [];
    return;
  }
  unonboarded = (await resp.json()) as Unonboarded[];
}

function presentOffices(): string[] {
  const seen = new Set<string>();
  for (const u of users) seen.add(u.office);
  return OFFICE_ORDER.filter((k) => seen.has(k)).concat(
    Array.from(seen).filter((k) => !OFFICE_ORDER.includes(k)).sort(),
  );
}

function buildOfficeFilters() {
  const container = document.getElementById("admin-team-office-filters")!;
  const present = presentOffices();
  const allBtn = `<button class="filter-pill${activeOffice === "all" ? " active" : ""}" data-office="all" type="button">${esc(t("team.filter.all") || "Alle")}</button>`;
  const pills = present
    .map((k) => `<button class="filter-pill${activeOffice === k ? " active" : ""}" data-office="${esc(k)}" type="button">${esc(officeLabel(k))}</button>`)
    .join("");
  container.innerHTML = allBtn + pills;
  container.querySelectorAll<HTMLButtonElement>(".filter-pill").forEach((btn) => {
    btn.addEventListener("click", () => {
      activeOffice = btn.dataset.office ?? "all";
      container.querySelectorAll(".filter-pill").forEach((p) => p.classList.remove("active"));
      btn.classList.add("active");
      render();
    });
  });
}

function userMatchesSearch(u: User): boolean {
  if (!searchQuery) return true;
  const q = searchQuery.toLowerCase();
  return (
    u.display_name.toLowerCase().includes(q) ||
    u.email.toLowerCase().includes(q) ||
    (u.job_title ?? "").toLowerCase().includes(q)
  );
}

function userMatchesOffice(u: User): boolean {
  if (activeOffice === "all") return true;
  if (u.office === activeOffice) return true;
  return (u.additional_offices ?? []).includes(activeOffice);
}

function officeOptions(selected: string): string {
  return offices
    .map((o) => `<option value="${esc(o.key)}"${o.key === selected ? " selected" : ""}>${esc(officeLabel(o.key))}</option>`)
    .join("");
}

function additionalOfficesEditor(selected: string[]): string {
  return offices
    .map((o) => {
      const checked = selected.includes(o.key) ? " checked" : "";
      return `<label class="admin-team-multi-opt"><input type="checkbox" data-additional="${esc(o.key)}"${checked} /> ${esc(officeLabel(o.key))}</label>`;
    })
    .join("");
}

function langOptions(selected: string): string {
  return ["de", "en"]
    .map((l) => `<option value="${l}"${l === selected ? " selected" : ""}>${l.toUpperCase()}</option>`)
    .join("");
}

function globalAdminCount(): number {
  return users.reduce((acc, u) => acc + (u.global_role === "global_admin" ? 1 : 0), 0);
}

function permissionCell(u: User): string {
  const cls = u.global_role === "global_admin" ? "admin-team-perm admin-team-perm-admin" : "admin-team-perm";
  return `<span class="${cls}">${esc(permissionLabel(u.global_role))}</span>`;
}

function permissionEditor(u: User): string {
  // Disable demoting the only remaining global_admin.
  const isLastAdmin = u.global_role === "global_admin" && globalAdminCount() <= 1;
  const standardOpt = `<option value="standard"${u.global_role === "standard" ? " selected" : ""}>${esc(permissionLabel("standard"))}</option>`;
  const adminOpt = `<option value="global_admin"${u.global_role === "global_admin" ? " selected" : ""}>${esc(permissionLabel("global_admin"))}</option>`;
  const disabled = isLastAdmin ? " disabled" : "";
  const title = isLastAdmin ? ` title="${esc(t("admin.team.permission.last_admin") || "Letzter Admin kann nicht degradiert werden.")}"` : "";
  return `<select class="admin-team-input" data-field="global_role"${disabled}${title}>${standardOpt}${adminOpt}</select>`;
}

function professionLabel(p: string | null | undefined): string {
  if (!p) return "";
  return tDyn(`projects.team.profession.${p}`) || p;
}

function professionCell(u: User): string {
  if (!u.profession) {
    return `<span class="admin-team-muted" title="${esc(t("admin.team.col.profession.none.hint") || "Keine Profession gesetzt — keine 4-Augen-Befugnis")}">${esc(t("projects.team.profession.none") || "(extern)")}</span>`;
  }
  return `<span class="projekt-team-profession">${esc(professionLabel(u.profession))}</span>`;
}

function professionEditor(u: User): string {
  const noneOpt = `<option value=""${!u.profession ? " selected" : ""}>${esc(t("admin.team.col.profession.none") || "(extern)")}</option>`;
  const opts = PROFESSION_VALUES.map(
    (p) => `<option value="${esc(p)}"${u.profession === p ? " selected" : ""}>${esc(professionLabel(p))}</option>`,
  ).join("");
  return `<select class="admin-team-input" data-field="profession">${noneOpt}${opts}</select>`;
}

function renderRow(u: User): string {
  if (editingId === u.id) return renderEditRow(u);
  const additional = (u.additional_offices ?? []).filter((o) => o !== u.office);
  const jobTitle = u.job_title ?? "";
  return `
    <tr data-user-id="${esc(u.id)}">
      <td class="entity-col-title">${esc(u.display_name)}</td>
      <td><a href="mailto:${esc(u.email)}">${esc(u.email)}</a></td>
      <td><span class="office-chip office-${esc(u.office)}">${esc(officeLabel(u.office))}</span></td>
      <td>${jobTitle ? esc(jobTitle) : "<span class=\"admin-team-muted\">—</span>"}</td>
      <td>${professionCell(u)}</td>
      <td>${permissionCell(u)}</td>
      <td>${additional.length ? additional.map((o) => esc(officeLabel(o))).join(", ") : "<span class=\"admin-team-muted\">—</span>"}</td>
      <td>${esc(u.lang.toUpperCase())}</td>
      <td class="entity-col-updated">${esc(fmtDate(u.created_at))}</td>
      <td class="admin-team-actions-cell">
        <button type="button" class="btn-link admin-team-edit" data-id="${esc(u.id)}" data-i18n="admin.team.row.edit">Bearbeiten</button>
        <button type="button" class="btn-link admin-team-delete" data-id="${esc(u.id)}" data-i18n="admin.team.row.delete">L&ouml;schen</button>
      </td>
    </tr>`;
}

function renderEditRow(u: User): string {
  const additional = u.additional_offices ?? [];
  const jobTitleList = JOB_TITLE_SUGGESTIONS.map((r) => `<option value="${esc(r)}" />`).join("");
  const jobTitle = u.job_title ?? "";
  return `
    <tr data-user-id="${esc(u.id)}" class="admin-team-edit-row">
      <td><input type="text" class="admin-team-input" data-field="display_name" value="${esc(u.display_name)}" /></td>
      <td><span class="admin-team-muted" title="E-Mail kann nicht ge&auml;ndert werden">${esc(u.email)}</span></td>
      <td><select class="admin-team-input" data-field="office">${officeOptions(u.office)}</select></td>
      <td>
        <input type="text" class="admin-team-input" data-field="job_title" value="${esc(jobTitle)}" list="admin-team-job-title-suggest-${esc(u.id)}" />
        <datalist id="admin-team-job-title-suggest-${esc(u.id)}">${jobTitleList}</datalist>
      </td>
      <td>${professionEditor(u)}</td>
      <td>${permissionEditor(u)}</td>
      <td class="admin-team-multi">${additionalOfficesEditor(additional)}</td>
      <td><select class="admin-team-input" data-field="lang">${langOptions(u.lang)}</select></td>
      <td class="entity-col-updated">${esc(fmtDate(u.created_at))}</td>
      <td class="admin-team-actions-cell">
        <button type="button" class="btn-primary admin-team-save" data-id="${esc(u.id)}" data-i18n="admin.team.row.save">Speichern</button>
        <button type="button" class="btn-cancel admin-team-cancel" data-id="${esc(u.id)}" data-i18n="admin.team.row.cancel">Abbrechen</button>
      </td>
    </tr>`;
}

function showFeedback(msg: string, isError: boolean) {
  const el = document.getElementById("admin-team-feedback")!;
  el.textContent = msg;
  el.className = "form-msg " + (isError ? "form-msg-error" : "form-msg-ok");
  el.style.display = "block";
  if (!isError) {
    setTimeout(() => { el.style.display = "none"; }, 3500);
  }
}

function render() {
  const tbody = document.getElementById("admin-team-tbody")!;
  const empty = document.getElementById("admin-team-empty")!;
  const count = document.getElementById("admin-team-count")!;

  const filtered = users.filter((u) => userMatchesOffice(u) && userMatchesSearch(u));
  count.textContent = `${filtered.length} / ${users.length}`;

  if (filtered.length === 0) {
    tbody.innerHTML = "";
    empty.style.display = "block";
    return;
  }
  empty.style.display = "none";

  // Stable sort: global admins first, then by display_name.
  const sorted = filtered.slice().sort((a, b) => {
    const aAdmin = a.global_role === "global_admin";
    const bAdmin = b.global_role === "global_admin";
    if (aAdmin && !bAdmin) return -1;
    if (bAdmin && !aAdmin) return 1;
    return a.display_name.localeCompare(b.display_name);
  });
  tbody.innerHTML = sorted.map(renderRow).join("");
  attachRowListeners();
}

function attachRowListeners() {
  document.querySelectorAll<HTMLButtonElement>(".admin-team-edit").forEach((b) => {
    b.addEventListener("click", () => {
      editingId = b.dataset.id ?? null;
      render();
    });
  });
  document.querySelectorAll<HTMLButtonElement>(".admin-team-cancel").forEach((b) => {
    b.addEventListener("click", () => {
      editingId = null;
      render();
    });
  });
  document.querySelectorAll<HTMLButtonElement>(".admin-team-save").forEach((b) => {
    b.addEventListener("click", () => saveRow(b.dataset.id!));
  });
  document.querySelectorAll<HTMLButtonElement>(".admin-team-delete").forEach((b) => {
    b.addEventListener("click", () => deleteRow(b.dataset.id!));
  });
}

async function saveRow(id: string) {
  const tr = document.querySelector<HTMLTableRowElement>(`tr[data-user-id="${id}"]`);
  if (!tr) return;
  const payload: Record<string, unknown> = {};
  tr.querySelectorAll<HTMLInputElement | HTMLSelectElement>("[data-field]").forEach((el) => {
    payload[el.dataset.field!] = el.value;
  });
  const additional: string[] = [];
  tr.querySelectorAll<HTMLInputElement>("[data-additional]").forEach((cb) => {
    if (cb.checked) additional.push(cb.dataset.additional!);
  });
  payload.additional_offices = additional;

  const resp = await fetch(`/api/admin/users/${id}`, {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });
  if (!resp.ok) {
    const body = await resp.json().catch(() => ({ error: resp.statusText }));
    showFeedback(body.error || "Fehler beim Speichern.", true);
    return;
  }
  const updated = (await resp.json()) as User;
  users = users.map((u) => (u.id === id ? updated : u));
  editingId = null;
  showFeedback(t("admin.team.feedback.saved") || "Gespeichert.", false);
  render();
}

async function deleteRow(id: string) {
  const u = users.find((x) => x.id === id);
  if (!u) return;
  const confirmMsg = (t("admin.team.confirm.delete") || "{name} wirklich löschen?").replace("{name}", u.display_name);
  if (!window.confirm(confirmMsg)) return;
  const resp = await fetch(`/api/admin/users/${id}`, { method: "DELETE" });
  if (!resp.ok && resp.status !== 204) {
    const body = await resp.json().catch(() => ({ error: resp.statusText }));
    showFeedback(body.error || "Löschen fehlgeschlagen.", true);
    return;
  }
  users = users.filter((x) => x.id !== id);
  showFeedback(t("admin.team.feedback.deleted") || "Gelöscht.", false);
  render();
}

function initSearch() {
  const input = document.getElementById("admin-team-search") as HTMLInputElement;
  input.addEventListener("input", () => {
    searchQuery = input.value;
    render();
  });
}

function openDirectAddModal() {
  const modal = document.getElementById("admin-direct-add-modal")!;
  const select = document.getElementById("admin-da-email") as HTMLSelectElement;
  const officeSel = document.getElementById("admin-da-office") as HTMLSelectElement;
  const fb = document.getElementById("admin-da-feedback")!;
  const nameField = document.getElementById("admin-da-name") as HTMLInputElement;
  const jobTitleField = document.getElementById("admin-da-role") as HTMLInputElement;

  fb.style.display = "none";
  nameField.value = "";
  jobTitleField.value = "";

  officeSel.innerHTML = officeOptions("munich");

  loadUnonboarded().then(() => {
    select.innerHTML = `<option value="">${esc(t("admin.team.direct_add.email.placeholder") || "Bitte auswählen...")}</option>` +
      unonboarded.map((u) => `<option value="${esc(u.email)}">${esc(u.email)}</option>`).join("");
    if (unonboarded.length === 0) {
      const noneMsg = t("admin.team.direct_add.empty") || "Keine offenen Konten.";
      select.innerHTML = `<option value="">${esc(noneMsg)}</option>`;
    }
  });

  modal.style.display = "flex";
}

function closeDirectAddModal() {
  document.getElementById("admin-direct-add-modal")!.style.display = "none";
}

function initDirectAddModal() {
  document.getElementById("admin-team-direct-add")!.addEventListener("click", openDirectAddModal);
  document.getElementById("admin-direct-add-close")!.addEventListener("click", closeDirectAddModal);
  document.getElementById("admin-da-cancel")!.addEventListener("click", closeDirectAddModal);

  const emailSel = document.getElementById("admin-da-email") as HTMLSelectElement;
  const nameField = document.getElementById("admin-da-name") as HTMLInputElement;
  emailSel.addEventListener("change", () => {
    if (!nameField.value && emailSel.value) {
      // Pre-fill from email local-part.
      const local = emailSel.value.split("@")[0] ?? "";
      nameField.value = local
        .split(/[._-]/)
        .map((s) => (s ? s[0].toUpperCase() + s.slice(1) : s))
        .join(" ")
        .trim();
    }
  });

  document.getElementById("admin-direct-add-modal")!.addEventListener("click", (e) => {
    if (e.target === e.currentTarget) closeDirectAddModal();
  });

  const form = document.getElementById("admin-direct-add-form") as HTMLFormElement;
  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    const fb = document.getElementById("admin-da-feedback")!;
    fb.style.display = "none";

    const officeSel = document.getElementById("admin-da-office") as HTMLSelectElement;
    const jobTitleField = document.getElementById("admin-da-role") as HTMLInputElement;

    const payload: Record<string, unknown> = {
      email: emailSel.value,
      display_name: nameField.value.trim(),
      office: officeSel.value,
      job_title: jobTitleField.value.trim() || "Associate",
      lang: "de",
    };

    const resp = await fetch("/api/admin/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
    });
    if (!resp.ok) {
      const body = await resp.json().catch(() => ({ error: resp.statusText }));
      fb.textContent = body.error || "Fehler.";
      fb.className = "form-msg form-msg-error";
      fb.style.display = "block";
      return;
    }
    const created = (await resp.json()) as User;
    users = users.concat(created);
    closeDirectAddModal();
    showFeedback(t("admin.team.feedback.added") || "Konto onboardet.", false);
    render();
  });
}

function initInviteButton() {
  document.getElementById("admin-team-invite")!.addEventListener("click", () => {
    document.getElementById("sidebar-invite-btn")?.click();
  });
}

// t-paliad-223 Slice B (#49) — "Konto direkt anlegen" modal. Creates both
// the auth.users row (via Supabase Admin API) and the paliad.users row in
// one POST. New user appears in dropdowns immediately. Welcome email with
// magic-link is sent by default; admin can opt out via the checkbox.
function openAddFullModal() {
  const modal = document.getElementById("admin-add-full-modal")!;
  const fb = document.getElementById("admin-af-feedback")!;
  const officeSel = document.getElementById("admin-af-office") as HTMLSelectElement;
  const emailField = document.getElementById("admin-af-email") as HTMLInputElement;
  const nameField = document.getElementById("admin-af-name") as HTMLInputElement;
  const jobTitleField = document.getElementById("admin-af-job-title") as HTMLInputElement;
  const profSel = document.getElementById("admin-af-profession") as HTMLSelectElement;
  const langSel = document.getElementById("admin-af-lang") as HTMLSelectElement;
  const sendWelcome = document.getElementById("admin-af-send-welcome") as HTMLInputElement;

  fb.style.display = "none";
  emailField.value = "";
  nameField.value = "";
  jobTitleField.value = "";
  profSel.value = "associate";
  langSel.value = "de";
  sendWelcome.checked = true;
  officeSel.innerHTML = officeOptions("munich");

  modal.style.display = "flex";
  emailField.focus();
}

function closeAddFullModal() {
  document.getElementById("admin-add-full-modal")!.style.display = "none";
}

function initAddFullModal() {
  document.getElementById("admin-team-add-full")!.addEventListener("click", openAddFullModal);
  document.getElementById("admin-af-close")!.addEventListener("click", closeAddFullModal);
  document.getElementById("admin-af-cancel")!.addEventListener("click", closeAddFullModal);
  document.getElementById("admin-add-full-modal")!.addEventListener("click", (e) => {
    if (e.target === e.currentTarget) closeAddFullModal();
  });

  const emailField = document.getElementById("admin-af-email") as HTMLInputElement;
  const nameField = document.getElementById("admin-af-name") as HTMLInputElement;
  // Pre-fill the display name from the email local-part the first time the
  // admin tabs out of the email field — mirrors the existing onboard flow.
  emailField.addEventListener("blur", () => {
    if (nameField.value || !emailField.value) return;
    const local = emailField.value.split("@")[0] ?? "";
    nameField.value = local
      .split(/[._-]/)
      .map((s) => (s ? s[0].toUpperCase() + s.slice(1) : s))
      .join(" ")
      .trim();
  });

  const form = document.getElementById("admin-add-full-form") as HTMLFormElement;
  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    const fb = document.getElementById("admin-af-feedback")!;
    fb.style.display = "none";

    const officeSel = document.getElementById("admin-af-office") as HTMLSelectElement;
    const jobTitleField = document.getElementById("admin-af-job-title") as HTMLInputElement;
    const profSel = document.getElementById("admin-af-profession") as HTMLSelectElement;
    const langSel = document.getElementById("admin-af-lang") as HTMLSelectElement;
    const sendWelcome = document.getElementById("admin-af-send-welcome") as HTMLInputElement;
    const submitBtn = document.getElementById("admin-af-submit") as HTMLButtonElement;

    const payload: Record<string, unknown> = {
      email: emailField.value.trim().toLowerCase(),
      display_name: nameField.value.trim(),
      office: officeSel.value,
      job_title: jobTitleField.value.trim() || "Associate",
      profession: profSel.value,
      lang: langSel.value,
      send_welcome_mail: sendWelcome.checked,
    };

    submitBtn.disabled = true;
    try {
      const resp = await fetch("/api/admin/users/full", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });
      if (!resp.ok) {
        const body = await resp.json().catch(() => ({ error: resp.statusText }));
        // Map two friendly cases inline; everything else surfaces the
        // server message so the admin can act on it.
        if (resp.status === 503) {
          fb.textContent = t("admin.team.add_full.error.unavailable")
            || "Add-User-Pfad ist nicht konfiguriert (SUPABASE_SERVICE_ROLE_KEY fehlt am Server).";
        } else if (resp.status === 409) {
          fb.textContent = body.error
            || (t("admin.team.add_full.error.email_exists")
              || "Es existiert bereits ein Konto für diese E-Mail — bitte 'Bestehendes Konto onboarden' verwenden.");
        } else {
          fb.textContent = body.error || (t("admin.team.add_full.error.generic") || "Fehler.");
        }
        fb.className = "form-msg form-msg-error";
        fb.style.display = "block";
        return;
      }
      const created = (await resp.json()) as User;
      users = users.concat(created);
      closeAddFullModal();
      showFeedback(t("admin.team.add_full.feedback.added") || "Konto angelegt.", false);
      render();
    } finally {
      submitBtn.disabled = false;
    }
  });
}

document.addEventListener("DOMContentLoaded", () => {
  initI18n();
  initSidebar();
  initSearch();
  initDirectAddModal();
  initAddFullModal();
  initInviteButton();
  onLangChange(() => {
    buildOfficeFilters();
    render();
  });
  loadAll();
});
