// Save-as-view modal for the FilterBar. Mirrors the create form on
// /views/new (frontend/src/client/views-editor.ts:168) but as a modal
// so the user can save the bar's current effective spec without
// leaving the page they're filtering on.
//
// On success, the new view appears in the "Meine Sichten" sidebar
// group on next render (the sidebar polls /api/user-views on init).

import { t } from "../i18n";
import type { FilterSpec, RenderSpec, UserView } from "../views/types";

export interface SaveModalResult {
  view: UserView;
}

const SLUG_REGEX = /^[a-z0-9][a-z0-9-]{0,62}$/;

export function openSaveModal(filter: FilterSpec, render: RenderSpec): Promise<SaveModalResult | null> {
  return new Promise((resolve) => {
    const dialog = document.createElement("dialog");
    dialog.className = "filter-bar-save-modal";

    dialog.innerHTML = `
      <form method="dialog" class="filter-bar-save-form">
        <h2>${t("views.bar.save.heading")}</h2>
        <label class="filter-bar-save-field">
          <span>${t("views.bar.save.field.name")}</span>
          <input type="text" name="name" required maxlength="100" autocomplete="off" />
        </label>
        <label class="filter-bar-save-field">
          <span>${t("views.bar.save.field.slug")}</span>
          <input type="text" name="slug" required maxlength="63" autocomplete="off" pattern="[a-z0-9][a-z0-9-]*" />
          <small>${t("views.bar.save.field.slug_hint")}</small>
        </label>
        <label class="filter-bar-save-checkbox">
          <input type="checkbox" name="show_count" />
          <span>${t("views.bar.save.field.show_count")}</span>
        </label>
        <p class="filter-bar-save-error" hidden></p>
        <div class="filter-bar-save-actions">
          <button type="button" class="btn-secondary" data-action="cancel">${t("views.bar.save.cancel")}</button>
          <button type="submit" class="btn-primary">${t("views.bar.save.confirm")}</button>
        </div>
      </form>
    `;

    document.body.appendChild(dialog);

    const form = dialog.querySelector<HTMLFormElement>(".filter-bar-save-form")!;
    const errorEl = dialog.querySelector<HTMLParagraphElement>(".filter-bar-save-error")!;
    const nameInput = form.elements.namedItem("name") as HTMLInputElement;
    const slugInput = form.elements.namedItem("slug") as HTMLInputElement;
    const showCount = form.elements.namedItem("show_count") as HTMLInputElement;
    const cancelBtn = dialog.querySelector<HTMLButtonElement>('[data-action="cancel"]')!;

    // Auto-derive slug from name as the user types — but only until
    // they touch the slug field manually.
    let slugDirty = false;
    nameInput.addEventListener("input", () => {
      if (!slugDirty) slugInput.value = derivedSlug(nameInput.value);
    });
    slugInput.addEventListener("input", () => { slugDirty = true; });

    const cleanup = () => {
      dialog.close();
      dialog.remove();
    };

    cancelBtn.addEventListener("click", () => {
      cleanup();
      resolve(null);
    });

    form.addEventListener("submit", async (e) => {
      e.preventDefault();
      errorEl.hidden = true;
      errorEl.textContent = "";

      const name = nameInput.value.trim();
      const slug = slugInput.value.trim();
      if (!name) {
        showError(errorEl, t("views.bar.save.error.name_required"));
        return;
      }
      if (!SLUG_REGEX.test(slug)) {
        showError(errorEl, t("views.bar.save.error.slug_format"));
        return;
      }

      const payload = {
        name,
        slug,
        filter_spec: filter,
        render_spec: render,
        show_count: showCount.checked,
      };
      try {
        const r = await fetch("/api/user-views", {
          method: "POST",
          credentials: "include",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
        if (r.status === 409) {
          showError(errorEl, t("views.bar.save.error.slug_taken"));
          return;
        }
        if (!r.ok) {
          const body = await r.json().catch(() => ({} as { error?: string }));
          showError(errorEl, body.error || `${r.status}: ${r.statusText}`);
          return;
        }
        const view = (await r.json()) as UserView;
        cleanup();
        resolve({ view });
      } catch (_e) {
        showError(errorEl, t("views.bar.save.error.network"));
      }
    });

    dialog.addEventListener("cancel", () => {
      cleanup();
      resolve(null);
    });

    dialog.showModal();
    nameInput.focus();
  });
}

function showError(el: HTMLElement, msg: string): void {
  el.textContent = msg;
  el.hidden = false;
}

function derivedSlug(name: string): string {
  return name
    .toLowerCase()
    .replace(/[äÄ]/g, "ae")
    .replace(/[öÖ]/g, "oe")
    .replace(/[üÜ]/g, "ue")
    .replace(/[ß]/g, "ss")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 63);
}
