<script lang="ts">
  import { browser } from "$app/environment";
  import Icon from "@iconify/svelte";
  import "$lib/iconify-offline";
  import BlockRenderer from "./BlockRenderer.svelte";
  import type { Translations } from "$lib/translations";
  import type { ResolvedBlock } from "$lib/block-types";
  import {
    selectModal,
    dismissKey,
    type ModalLike,
  } from "$lib/modal-match";

  interface ModalEntry extends ModalLike {
    trigger?: "immediate" | "delay" | "scroll" | "exit_intent";
    delaySeconds?: number;
    scrollPercent?: number;
    content?: unknown[];
    dismissible?: boolean;
    size?: "sm" | "md" | "lg";
  }

  let {
    modals = [],
    pathname,
    translations = {},
  }: {
    modals?: ModalEntry[];
    pathname: string;
    translations?: Translations | null;
  } = $props();

  let active = $state<ModalEntry | null>(null);
  let open = $state(false);
  let dontShowAgain = $state(false);

  /** Nur diese Session ausgeblendet (X/Escape/Backdrop). */
  function sessionKey(m: ModalEntry): string {
    return `modal-session:${m.slug ?? m._slug ?? "unknown"}:${m.version ?? ""}`;
  }

  function isDismissed(m: ModalEntry): boolean {
    try {
      if (localStorage.getItem(dismissKey(m))) return true;
      if (sessionStorage.getItem(sessionKey(m))) return true;
    } catch {
      /* Storage gesperrt (Private Mode) → nicht als dismissed werten. */
    }
    return false;
  }

  function close(permanent: boolean) {
    const m = active;
    open = false;
    if (!m) return;
    try {
      if (permanent && m.dismissible !== false) {
        localStorage.setItem(dismissKey(m), "1");
      } else {
        sessionStorage.setItem(sessionKey(m), "1");
      }
    } catch {
      /* Storage gesperrt → Modal kommt beim nächsten Load wieder. */
    }
  }

  function onKeydown(e: KeyboardEvent) {
    if (e.key === "Escape" && open) close(dontShowAgain);
  }

  const sizeClass = $derived(
    active?.size === "sm"
      ? "max-w-md"
      : active?.size === "lg"
        ? "max-w-3xl"
        : "max-w-xl",
  );

  // Kandidat je Route neu wählen und Trigger scharfschalten. Cleanup läuft vor
  // jedem Re-Run (Navigation) und beim Destroy — entfernt Timer/Listener.
  $effect(() => {
    if (!browser) return;
    const path = pathname;
    const list = modals ?? [];

    open = false;
    dontShowAgain = false;
    const m = selectModal<ModalEntry>(list, path, Date.now(), isDismissed);
    active = m;
    if (!m) return;

    const show = () => {
      open = true;
    };
    let removeScroll: (() => void) | null = null;
    let removeExit: (() => void) | null = null;
    let timer: ReturnType<typeof setTimeout> | null = null;

    switch (m.trigger ?? "delay") {
      case "immediate":
        show();
        break;
      case "delay":
        timer = setTimeout(show, Math.max(0, m.delaySeconds ?? 3) * 1000);
        break;
      case "scroll": {
        const pct = Math.min(100, Math.max(1, m.scrollPercent ?? 30));
        const onScroll = () => {
          const h =
            document.documentElement.scrollHeight - window.innerHeight;
          const scrolled = h > 0 ? (window.scrollY / h) * 100 : 100;
          if (scrolled >= pct) {
            show();
            removeScroll?.();
            removeScroll = null;
          }
        };
        window.addEventListener("scroll", onScroll, { passive: true });
        removeScroll = () =>
          window.removeEventListener("scroll", onScroll);
        onScroll(); // Fall: Seite kürzer als Trigger → sofort
        break;
      }
      case "exit_intent": {
        // Nur Desktop (feiner Zeiger) — Touch hat kein Exit-Intent.
        if (window.matchMedia("(pointer: fine)").matches) {
          const onOut = (e: MouseEvent) => {
            if (e.clientY <= 0) show();
          };
          document.addEventListener("mouseout", onOut);
          removeExit = () =>
            document.removeEventListener("mouseout", onOut);
        }
        break;
      }
    }

    return () => {
      if (timer) clearTimeout(timer);
      removeScroll?.();
      removeExit?.();
    };
  });

  const blocks = $derived((active?.content ?? []) as ResolvedBlock[]);
</script>

<svelte:window on:keydown={onKeydown} />

{#if open && active}
  <div
    class="fixed inset-0 z-[9998] flex items-center justify-center bg-black/70 p-4 backdrop-blur-sm"
    role="presentation"
    onclick={() => close(dontShowAgain)}
  >
    <div
      class="relative w-full {sizeClass} max-h-[90vh] overflow-y-auto rounded-lg bg-white p-6 shadow-2xl md:p-8"
      role="dialog"
      aria-modal="true"
      onclick={(e) => e.stopPropagation()}
    >
      <button
        type="button"
        onclick={() => close(dontShowAgain)}
        class="absolute top-3 right-3 rounded-full p-2 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-800"
        aria-label="Schließen"
      >
        <Icon icon="lucide:x" class="size-5" aria-hidden="true" />
      </button>

      <div class="content-modal-body">
        {#each blocks as block (block)}
          <BlockRenderer {block} {translations} />
        {/each}
      </div>

      {#if active.dismissible !== false}
        <div class="mt-6 flex items-center justify-between gap-4 border-t border-gray-200 pt-4">
          <label class="flex cursor-pointer items-center gap-2 text-sm text-gray-600">
            <input
              type="checkbox"
              class="size-4 accent-wald-700"
              bind:checked={dontShowAgain}
            />
            <span>Dauerhaft nicht mehr anzeigen</span>
          </label>
          <button
            type="button"
            class="rounded-md bg-wald-700 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-wald-800"
            onclick={() => close(dontShowAgain)}
          >
            Schließen
          </button>
        </div>
      {/if}
    </div>
  </div>
{/if}
