// broadcast.ts — bulk team-email compose modal (t-paliad-147 / issue #7,
// retrofitted onto the unified modal primitive in t-paliad-217 Slice D).
//
// Exposes openBroadcastModal({ recipients, projectIDs }) which the /team
// page calls when the "E-Mail an Auswahl" button is clicked. The modal
// collects subject + body + (optional) template and posts to
// /api/team/broadcast. On success it shows a per-recipient send report
// and closes after a short delay.
//
// Per-recipient privacy: each member receives their own envelope. The
// modal lists every addressee so the sender knows exactly who will be
// mailed; there is no surprise to-line.
//
// Migration notes (t-paliad-217 Slice D): the shell, ESC, backdrop,
// close button, and browser back-button are now owned by openModal().
// The body is built imperatively so the submit handler can read form
// state from the modal-body element it constructed.

import { t } from "./i18n";
import { openModal } from "./components/modal";

export interface BroadcastRecipient {
  user_id: string;
  email: string;
  display_name: string;
  first_name: string;
  role_on_project: string;
}

export interface OpenBroadcastModalArgs {
  recipients: BroadcastRecipient[];
  projectID?: string | null;
  projectIDs?: string[];
  offices?: string[];
  roles?: string[];
}

interface EmailTemplateOption {
  key: string;
  subject: string;
  body: string;
  is_default: boolean;
}

interface BroadcastResult {
  sent: number;
  failed: number;
  total: number;
}

const RECIPIENT_CAP = 100;

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

// firstName extracts the first whitespace-separated token from a display
// name. "Anna von Beispiel" → "Anna". Empty input → "".
export function firstName(displayName: string): string {
  return displayName.trim().split(/\s+/)[0] ?? "";
}

// buildMailtoHref produces a `mailto:` URL with every recipient queued
// in the To: field, comma-separated per RFC 6068. The `?` form is
// preserved as a future hook for default subject/body — kept empty here
// so users compose their own message in their mail client. Empty input
// returns "mailto:" so the button still renders without a JS error.
export function buildMailtoHref(recipients: BroadcastRecipient[]): string {
  const addrs = recipients
    .map((r) => r.email.trim())
    .filter((e) => e.length > 0)
    .map((e) => encodeURIComponent(e));
  if (!addrs.length) return "mailto:";
  return `mailto:${addrs.join(",")}`;
}

export function openBroadcastModal(args: OpenBroadcastModalArgs): void {
  if (!args.recipients.length) {
    alert(t("team.broadcast.error.no_recipients") || "Keine Empfänger ausgewählt.");
    return;
  }
  if (args.recipients.length > RECIPIENT_CAP) {
    alert(
      (t("team.broadcast.error.too_many") || "Empfängerlimit ({cap}) überschritten.").replace(
        "{cap}",
        String(RECIPIENT_CAP),
      ),
    );
    return;
  }

  const body = renderBody(args);
  wireBody(body);

  void openModal<BroadcastResult>({
    title: t("team.broadcast.title") || "E-Mail an Auswahl",
    body,
    size: "lg",
    primary: {
      label: `${t("team.broadcast.send") || "Senden"} (${args.recipients.length})`,
      handler: async (close) => {
        await onSubmit(body, args, close);
      },
    },
    secondary: { label: t("common.cancel") || "Abbrechen" },
  });
}

function renderBody(args: OpenBroadcastModalArgs): HTMLElement {
  const root = document.createElement("div");
  root.className = "broadcast-body";
  const count = args.recipients.length;
  const previewItems = args.recipients
    .slice(0, 5)
    .map((r) => esc(r.display_name) + " &lt;" + esc(r.email) + "&gt;")
    .join(", ");
  const more = count > 5 ? ` +${count - 5}` : "";
  const fullList = args.recipients
    .map(
      (r) =>
        `<li><span class="broadcast-recip-name">${esc(r.display_name)}</span> <span class="broadcast-recip-email">&lt;${esc(r.email)}&gt;</span>${
          r.role_on_project ? ` <span class="broadcast-recip-role">${esc(r.role_on_project)}</span>` : ""
        }</li>`,
    )
    .join("");

  root.innerHTML = `
    <div class="broadcast-recipient-summary">
      <strong>${esc(t("team.broadcast.recipients") || "Empfänger")}: ${count}</strong>
      <button type="button" class="link-button" data-broadcast-toggle-recipients>${esc(t("team.broadcast.show_all") || "Alle anzeigen")}</button>
      <a class="link-button broadcast-mailto" href="${buildMailtoHref(args.recipients)}" data-broadcast-mailto title="${esc(t("team.broadcast.mailto.tooltip") || "Im lokalen Mail-Client öffnen")}">
        ${esc(t("team.broadcast.mailto.label") || "Im Mail-Client öffnen")}
      </a>
      <div class="broadcast-recipient-preview">${previewItems}${more}</div>
      <div class="broadcast-recipient-list hidden" data-broadcast-recipient-list>
        <ul>${fullList}</ul>
      </div>
    </div>

    <div class="form-field">
      <label for="broadcast-template-select">${esc(t("team.broadcast.template") || "Vorlage")} <span class="muted">(${esc(t("team.broadcast.template_optional") || "optional")})</span></label>
      <select id="broadcast-template-select" data-broadcast-template>
        <option value="">${esc(t("team.broadcast.template_freeform") || "Freitext")}</option>
        <option value="invitation">${esc(t("team.broadcast.template.invitation") || "Einladung")}</option>
        <option value="deadline_digest">${esc(t("team.broadcast.template.deadline_digest") || "Frist-Digest")}</option>
      </select>
    </div>

    <div class="form-field">
      <label for="broadcast-subject">${esc(t("team.broadcast.subject") || "Betreff")}</label>
      <input type="text" id="broadcast-subject" data-broadcast-subject required maxlength="200" />
    </div>

    <div class="form-field">
      <label for="broadcast-body">${esc(t("team.broadcast.body") || "Nachricht")}</label>
      <textarea id="broadcast-body" data-broadcast-body required rows="12" placeholder="${esc(t("team.broadcast.body_placeholder") || "Hallo {{first_name}}, …")}"></textarea>
    </div>

    <p class="broadcast-hint muted">
      ${esc(t("team.broadcast.placeholders_hint") || "Platzhalter: {{name}}, {{first_name}}, {{role_on_project}}")}
    </p>
    <p class="broadcast-hint muted">
      ${esc(t("team.broadcast.markdown_hint") || "Markdown unterstützt: **fett**, *kursiv*, [Link](https://...), - Aufzählung.")}
    </p>

    <div class="broadcast-error hidden" data-broadcast-error></div>
    <div class="broadcast-success hidden" data-broadcast-success></div>
  `;
  return root;
}

function wireBody(body: HTMLElement): void {
  // Recipient list toggle.
  body.querySelector("[data-broadcast-toggle-recipients]")?.addEventListener("click", () => {
    const list = body.querySelector<HTMLDivElement>("[data-broadcast-recipient-list]");
    if (!list) return;
    list.classList.toggle("hidden");
  });

  // Template dropdown — populates subject/body from the selected template.
  const templateSelect = body.querySelector<HTMLSelectElement>("[data-broadcast-template]");
  templateSelect?.addEventListener("change", async () => {
    const key = templateSelect.value;
    if (!key) return;
    const lang = (document.documentElement.lang || "de") as "de" | "en";
    try {
      const res = await fetch(`/api/admin/email-templates/${encodeURIComponent(key)}/${lang}`);
      if (!res.ok) return;
      const tpl = (await res.json()) as EmailTemplateOption;
      const subjectInput = body.querySelector<HTMLInputElement>("[data-broadcast-subject]");
      const bodyInput = body.querySelector<HTMLTextAreaElement>("[data-broadcast-body]");
      if (subjectInput) subjectInput.value = stripGoTemplate(tpl.subject);
      if (bodyInput) bodyInput.value = stripGoTemplate(tpl.body);
    } catch {
      /* template load failure is non-fatal — sender keeps freeform mode. */
    }
  });
}

async function onSubmit(
  body: HTMLElement,
  args: OpenBroadcastModalArgs,
  close: (result: BroadcastResult) => void,
): Promise<void> {
  const subject = (body.querySelector<HTMLInputElement>("[data-broadcast-subject]")?.value ?? "").trim();
  const bodyText = (body.querySelector<HTMLTextAreaElement>("[data-broadcast-body]")?.value ?? "").trim();
  const templateKey = body.querySelector<HTMLSelectElement>("[data-broadcast-template]")?.value ?? "";
  const errEl = body.querySelector<HTMLDivElement>("[data-broadcast-error]");
  const okEl = body.querySelector<HTMLDivElement>("[data-broadcast-success]");
  errEl?.classList.add("hidden");
  okEl?.classList.add("hidden");

  if (!subject) {
    showError(errEl, t("team.broadcast.error.subject_required") || "Betreff ist erforderlich.");
    return;
  }
  if (!bodyText) {
    showError(errEl, t("team.broadcast.error.body_required") || "Nachricht ist erforderlich.");
    return;
  }

  // The modal primary button lives in the footer (owned by openModal),
  // not in the body. We surface "sending..." feedback via the in-body
  // success/error areas; the primary button stays clickable but the
  // server-side idempotency + RECIPIENT_CAP make double-clicks safe.
  const recipientFilter: Record<string, unknown> = {};
  if (args.projectIDs?.length) recipientFilter.project_ids = args.projectIDs;
  if (args.projectID) recipientFilter.project_id = args.projectID;
  if (args.offices?.length) recipientFilter.offices = args.offices;
  if (args.roles?.length) recipientFilter.roles = args.roles;

  const lang = (document.documentElement.lang === "en" ? "en" : "de");

  try {
    const res = await fetch("/api/team/broadcast", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        project_id: args.projectID ?? null,
        subject,
        body: bodyText,
        template_key: templateKey || undefined,
        lang,
        recipient_filter: recipientFilter,
        recipients: args.recipients,
      }),
    });
    if (!res.ok) {
      const errBody = await res.json().catch(() => ({ error: "Send failed" }));
      showError(errEl, (errBody as { error?: string }).error || "Send failed");
      return;
    }
    const report = (await res.json()) as BroadcastResult;
    if (okEl) {
      okEl.classList.remove("hidden");
      const tpl = t("team.broadcast.success") || "{sent} von {total} Mails versandt ({failed} fehlgeschlagen).";
      okEl.textContent = tpl
        .replace("{sent}", String(report.sent))
        .replace("{total}", String(report.total))
        .replace("{failed}", String(report.failed));
    }
    // Give the sender a moment to see the report, then close.
    setTimeout(() => close(report), 2500);
  } catch (e) {
    showError(errEl, String(e));
  }
}

function showError(el: HTMLDivElement | null | undefined, msg: string) {
  if (!el) return;
  el.textContent = msg;
  el.classList.remove("hidden");
}

// stripGoTemplate is best-effort: existing email templates carry
// `{{define "content"}}` wrappers and Go-template branches the broadcast
// compose form can't honour. The bulk-send pipeline expects plain
// Markdown + the placeholder set documented in the modal, so we strip
// the template directives before populating the textarea. Senders can
// still edit further.
function stripGoTemplate(src: string): string {
  return src
    .replace(/\{\{\s*(define|end|block|if|else|range|with)\b[^}]*\}\}/g, "")
    .trim();
}
