<script lang="ts">
  import { getBlockLayoutClasses } from "$lib/block-layout";
  import type {
    CalendarBlockData,
    CalendarItemData,
  } from "$lib/block-types";
  import { t as tStatic, T } from "$lib/translations";
  import type { Translations } from "$lib/translations";
  import "$lib/iconify-offline";
  import Icon from "@iconify/svelte";

  type EventCardItem = CalendarItemData & {
    date: Date | null;
    timeStr: string;
  };

  let { block, translations = {} }: { block: CalendarBlockData; translations?: Translations | null } = $props();

  function t(key: string, replacements?: Record<string, string | number>) {
    return tStatic(translations ?? null, key, replacements);
  }

  const layoutClasses = $derived(getBlockLayoutClasses(block.layout));

  const items = $derived.by(() => {
    const raw = block.items ?? [];
    return raw
      .filter(
        (x): x is CalendarItemData =>
          typeof x === "object" &&
          x !== null &&
          "terminZeit" in x &&
          "title" in x,
      )
      .map((x) => ({
        ...x,
        date: parseDate(x.terminZeit),
        timeStr: formatTime(x.terminZeit),
      }))
      .filter((x) => x.date)
      .sort((a, b) => (a.date!.getTime() ?? 0) - (b.date!.getTime() ?? 0));
  });

  function parseDate(iso: string): Date | null {
    const d = new Date(iso);
    return isNaN(d.getTime()) ? null : d;
  }

  /** Link aus calendar_item: API kann string (URL) oder aufgelöstes Objekt (_slug oder url) liefern. */
  function getEventLinkHref(link: unknown): string {
    if (typeof link === "string" && link) return link;
    if (link && typeof link === "object") {
      const o = link as { url?: string; _slug?: string };
      if (typeof o.url === "string" && o.url) return o.url;
      if (typeof o._slug === "string" && o._slug)
        return `/post/${encodeURIComponent(o._slug)}`;
    }
    return "";
  }

  function formatTime(iso: string): string {
    const d = new Date(iso);
    if (isNaN(d.getTime())) return "";
    const h = d.getHours();
    const m = d.getMinutes();
    if (h === 0 && m === 0) return "";
    return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")} Uhr`;
  }

  function dayKey(d: Date): string {
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
  }

  const eventsByDay = $derived.by(() => {
    const map = new Map<string, typeof items>();
    for (const item of items) {
      if (!item.date) continue;
      const key = dayKey(item.date);
      if (!map.has(key)) map.set(key, []);
      map.get(key)!.push(item);
    }
    return map;
  });

  let currentMonth = $state(new Date());
  let selectedDay = $state<string | null>(null);

  const year = $derived(currentMonth.getFullYear());
  const month = $derived(currentMonth.getMonth());
  const monthLabel = $derived(
    currentMonth.toLocaleDateString("de-DE", {
      month: "long",
      year: "numeric",
    }),
  );

  const daysInMonth = $derived.by(() => {
    const first = new Date(year, month, 1);
    const last = new Date(year, month + 1, 0);
    const count = last.getDate();
    const startWeekday = (first.getDay() + 6) % 7;
    return { count, startWeekday, last };
  });

  const calendarDays = $derived.by(() => {
    const { count, startWeekday } = daysInMonth;
    const empty = Array(startWeekday).fill(null);
    const days = Array.from(
      { length: count },
      (_, i) => new Date(year, month, i + 1),
    );
    return [...empty, ...days];
  });

  const selectedDayEvents = $derived(
    selectedDay ? (eventsByDay.get(selectedDay) ?? []) : [],
  );

  /** Nächste 3 Termine ab heute – zur Laufzeit gefiltert. */
  const nextUpcomingEvents = $derived.by(() => {
    const startOfToday = new Date();
    startOfToday.setHours(0, 0, 0, 0);
    const todayMs = startOfToday.getTime();
    return items
      .filter((item) => item.date && item.date.getTime() >= todayMs)
      .slice(0, 3);
  });

  function prevMonth() {
    currentMonth = new Date(year, month - 1);
    selectedDay = null;
  }

  function nextMonth() {
    currentMonth = new Date(year, month + 1);
    selectedDay = null;
  }

  function selectDay(key: string) {
    selectedDay = selectedDay === key ? null : key;
  }

  const todayKey = $derived(dayKey(new Date()));

  const weekdays = $derived([
    t(T.calendar_weekday_mo),
    t(T.calendar_weekday_di),
    t(T.calendar_weekday_mi),
    t(T.calendar_weekday_do),
    t(T.calendar_weekday_fr),
    t(T.calendar_weekday_sa),
    t(T.calendar_weekday_so),
  ]);
</script>

<div
  class="{layoutClasses} w-full min-w-0 calendar-block border border-stein-200 overflow-hidden"
  data-block-type="calendar"
  data-block-slug={block._slug}
>
  {#snippet eventCard(item: EventCardItem)}
    {@const eventHref = getEventLinkHref(item.link)}
    <li class="bg-himmel-100 p-2">
      <div class="flex gap-1">
        {#if item.date}
          <div class="text-xs text-stein-500 mb-0.5">
            {item.date.toLocaleDateString("de-DE", {
              weekday: "short",
              day: "numeric",
              month: "short",
            })}
          </div>
          {#if item.timeStr}
            <span class="text-xs text-stein-600">/</span>
          {/if}
        {/if}
        {#if item.timeStr}
          <div class="text-xs text-stein-600">
            {item.timeStr}
            {t(T.calendar_time_suffix)}
          </div>
        {/if}
      </div>
      {#if eventHref}
        <a
          href={eventHref}
          target="_blank"
          rel="noopener noreferrer"
          class="text-base font-medium text-stein-900 text-himmel-600 hover:text-himmel-700 hover:underline"
        >
          {item.title}
        </a>
      {:else}
        <div class="text-base font-medium text-stein-900">{item.title}</div>
      {/if}

      {#if item.description}
        <p class="text-sm font-light text-stein-600 mb-0! line-clamp-3">
          {item.description}
        </p>
        {#if eventHref}
          <a
            href={eventHref}
            target="_blank"
            rel="noopener noreferrer"
            class="inline-flex items-center gap-1 mt-2 text-sm text-himmel-600 hover:text-himmel-700"
          >
            {t(T.calendar_more_info)}
            <Icon
              icon="mdi:open-in-new"
              class="size-4"
              aria-hidden="true"
            />
          </a>
        {/if}
      {:else if eventHref}
        <a
          href={eventHref}
          target="_blank"
          rel="noopener noreferrer"
          class="inline-flex items-center gap-1 mt-2 text-sm text-himmel-600 hover:text-himmel-700"
        >
          {t(T.calendar_more_info)}
          <Icon
            icon="mdi:open-in-new"
            class="size-4"
            aria-hidden="true"
          />
        </a>
      {/if}
    </li>
  {/snippet}

  {#if block.title}
    <h3 class="text-lg font-semibold text-stein-900 px-4 pt-4 pb-2">
      {block.title}
    </h3>
  {/if}

  <div class="calendar-grid-wrapper grid w-full grid-cols-1 gap-0">
    <!-- Links: Kalender -->
    <div class="calendar-column min-h-full p-4 flex flex-col bg-himmel-800 text-himmel-100 shadow-sm">
      <div class="flex items-center justify-between gap-2 mb-4">
        <button
          type="button"
          class="p-2 rounded-xs text-himmel-100 hover:bg-himmel-700 hover:text-himmel-50 transition-colors"
          aria-label={t(T.calendar_prev_month)}
          onclick={prevMonth}
        >
          <Icon icon="mdi:chevron-left" class="size-5" aria-hidden="true" />
        </button>
        <span
          class="text-sm font-medium text-himmel-100 capitalize whitespace-nowrap"
          >{monthLabel}</span
        >
        <button
          type="button"
          class="p-2 rounded-xs text-himmel-100 hover:bg-himmel-700 hover:text-himmel-50 transition-colors"
          aria-label={t(T.calendar_next_month)}
          onclick={nextMonth}
        >
          <Icon icon="mdi:chevron-right" class="size-5" aria-hidden="true" />
        </button>
      </div>

      <div class="grid grid-cols-7 gap-0.5 text-center text-sm">
        {#each weekdays as w}
          <div class="py-1.5 text-xs font-medium text-himmel-100 opacity-80">{w}</div>
        {/each}
        {#each calendarDays as d}
          {#if d === null}
            <div class="aspect-square" aria-hidden="true"></div>
          {:else}
            {@const key = dayKey(d)}
            {@const isCurrentMonth = d.getMonth() === month}
            {@const events = eventsByDay.get(key) ?? []}
            {@const hasEvents = events.length > 0}
            {@const isSelected = selectedDay === key}
            {@const isFuture = key >= todayKey}
            {#if hasEvents}
              <button
                type="button"
                class="relative aspect-square rounded-xs flex flex-col items-center justify-center min-w-0 transition-colors cursor-pointer {isCurrentMonth
                  ? 'text-himmel-100 hover:bg-himmel-700'
                  : 'text-himmel-100 opacity-60 hover:opacity-80'} bg-himmel-700/50 font-semibold hover:bg-himmel-600 {isSelected
                  ? 'ring-2 ring-himmel-400 bg-himmel-600'
                  : ''}"
                onclick={() => selectDay(key)}
              >
                <span class="text-xs">{d.getDate()}</span>
                <span
                  class="absolute -bottom-1 -right-1 inline-flex items-center justify-center min-w-3.5 h-3.5 px-0.5 rounded-full text-stein-0 text-[9px] font-medium leading-none {isFuture ? 'bg-wald-400' : 'bg-error'}"
                  aria-hidden="true"
                >
                  {events.length}
                </span>
              </button>
            {:else}
              <div
                class="relative aspect-square rounded-xs flex flex-col items-center justify-center min-w-0 cursor-default {isCurrentMonth
                  ? 'text-himmel-100'
                  : 'text-himmel-100 opacity-50'}"
              >
                <span class="text-xs">{d.getDate()}</span>
              </div>
            {/if}
          {/if}
        {/each}
      </div>
    </div>

    <!-- Rechts: Events -->
    <div class="calendar-events-wrapper min-h-0">
      <div
        class="calendar-events-panel border-t border-stein-200 p-4 bg-stein-0/50 flex flex-col overflow-hidden"
      >
      {#if items.length === 0}
        <p class="text-sm text-stein-500 mt-2">{t(T.calendar_no_events)}</p>
      {:else if selectedDay}
        <p class="text-xs font-medium text-stein-500 mb-2">
          {new Date(selectedDay + "T12:00:00").toLocaleDateString("de-DE", {
            weekday: "long",
            day: "numeric",
            month: "long",
          })}
        </p>
        <ul class="m-0! p-0! flex-1 min-h-0 overflow-auto flex flex-col gap-2">
          {#each selectedDayEvents as item}
            {@render eventCard(item)}
          {/each}
        </ul>
      {:else if nextUpcomingEvents.length > 0}
        <p class="text-xs uppercase font-medium text-stein-500">
          {t(T.calendar_next_events)}
        </p>
        <ul
          class="space-y-3 m-0! p-0! flex-1 min-h-0 overflow-auto flex flex-col gap-2"
        >
          {#each nextUpcomingEvents as item}
            {@render eventCard(item)}
          {/each}
        </ul>
      {:else}
        <p class="text-sm text-stein-500 mt-2">{t(T.calendar_select_day)}</p>
      {/if}
      </div>
    </div>
  </div>
</div>
