<script lang="ts">
  import { listEntryTemplates, type EntryTemplateItemDto } from "$lib/backend/templates";
  import CalendarWidget from "$lib/components/CalendarWidget.svelte";
  import { entriesBusyStore, entriesStore } from "$lib/stores/entries";
  import { createFragmentDraft, fragmentsStore } from "$lib/stores/fragments";
  import { createListDraft, createListFromLabel, listsStore } from "$lib/stores/lists";
  import { createTodoListDraft, createTodoListFromLabel, serializeTodoList, todoListsStore, todosStore } from "$lib/stores/todos";

  export let activeSection = "entries";
  export let activeDocumentId = "";
  export let templateRefreshToken = 0;
  export let onOpenDocument: (doc: { id: string; label: string; initialContent: string }) => void = () => {};
  export let onEditItem: (doc: { id: string; label: string; initialContent: string }) => void = () => {};
  export let onDeleteItem: (doc: { id: string; label: string }) => void = () => {};

  let showNewItemInput = false;
  let newItemName = "";
  let newItemInput: HTMLInputElement | null = null;
  let createTemplateMode = false;

  type SidePanelItem = {
    id: string;
    label: string;
    initialContent: string;
  };
  let todoDocuments: SidePanelItem[] = [];
  let customCalendarEntries: SidePanelItem[] = [];
  let templateItems: SidePanelItem[] = [];
  let templatesBusy = false;
  let templateError = "";
  let wasEntriesSection = false;
  let lastTemplateRefreshToken = -1;

  const sectionTitles: Record<string, string> = {
    entries: "Entries",
    calendar: "Calendar",
    fragments: "Fragments",
    todos: "To-Do List",
    lists: "Lists"
  };

  const today = new Date();
  let calendarYear = today.getFullYear();
  let calendarMonth = today.getMonth();
  let calendarMonthLabel = new Date(calendarYear, calendarMonth, 1).toLocaleString(undefined, {
    month: "long"
  });
  let selectedCalendarDate: { year: number; month: number; day: number; key: string } | null = {
    year: today.getFullYear(),
    month: today.getMonth(),
    day: today.getDate(),
    key: `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`
  };

  function handleVisibleMonthChange(payload: { year: number; month: number; label: string }) {
    calendarYear = payload.year;
    calendarMonth = payload.month;
    calendarMonthLabel = payload.label;
  }

  function toMonthKey(year: number, month: number): string {
    return `${year}-${String(month + 1).padStart(2, "0")}`;
  }

  function toDateKey(year: number, month: number, day: number): string {
    return `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
  }

  function handleSelectedDateChange(payload: { year: number; month: number; day: number; key: string }) {
    selectedCalendarDate = payload;
  }

  function toTemplateStoreId(filePath: string): string {
    return `entries/template-file/${encodeURIComponent(filePath)}`;
  }

  function toTemplateLabel(fileName: string): string {
    return fileName.replace(/\.template\.md$/i, "");
  }

  function mapTemplateDto(item: EntryTemplateItemDto): SidePanelItem {
    return {
      id: toTemplateStoreId(item.filePath),
      label: toTemplateLabel(item.fileName),
      initialContent: ""
    };
  }

  async function refreshTemplates() {
    if (activeSection !== "entries") return;
    templatesBusy = true;
    templateError = "";
    try {
      const templates = await listEntryTemplates();
      templateItems = templates.map(mapTemplateDto);
    } catch (error) {
      templateError = String(error);
      templateItems = [];
    } finally {
      templatesBusy = false;
    }
  }

  function daysInMonth(year: number, month: number): number {
    return new Date(year, month + 1, 0).getDate();
  }

  function getCalendarEntries(year: number, month: number): SidePanelItem[] {
    const monthKey = toMonthKey(year, month);
    const shortLabel = new Date(year, month, 1).toLocaleString(undefined, {
      month: "short",
      year: "numeric"
    });
    const totalDays = daysInMonth(year, month);
    const anchors = [3, 10, 17, 24].map((day) => Math.min(day, totalDays));

    const entries: Array<SidePanelItem & { day: number; dateKey: string }> = [
      {
        id: `calendar/${monthKey}/overview`,
        label: `${shortLabel} Overview`,
        initialContent: `# ${shortLabel} Overview\n\nMonthly highlights and notes.`,
        day: anchors[0],
        dateKey: toDateKey(year, month, anchors[0])
      },
      {
        id: `calendar/${monthKey}/goals`,
        label: `${shortLabel} Goals`,
        initialContent: `# ${shortLabel} Goals\n\n- Goal 1\n- Goal 2\n- Goal 3`,
        day: anchors[1],
        dateKey: toDateKey(year, month, anchors[1])
      },
      {
        id: `calendar/${monthKey}/review`,
        label: `${shortLabel} Review`,
        initialContent: `# ${shortLabel} Review\n\nWhat went well and what to improve next month.`,
        day: anchors[2],
        dateKey: toDateKey(year, month, anchors[2])
      },
      {
        id: `calendar/${monthKey}/notes`,
        label: `${shortLabel} Notes`,
        initialContent: `# ${shortLabel} Notes\n\nFreeform notes for this month.`,
        day: anchors[3],
        dateKey: toDateKey(year, month, anchors[3])
      }
    ];

    const selected = selectedCalendarDate;
    const isSelectedInVisibleMonth = selected && selected.year === year && selected.month === month;

    if (!isSelectedInVisibleMonth || !selected) {
      return entries.sort((a, b) => a.day - b.day);
    }

    const selectedDay = selected.day;
    return entries
      .sort((a, b) => {
        const distA = Math.abs(a.day - selectedDay);
        const distB = Math.abs(b.day - selectedDay);
        if (distA !== distB) return distA - distB;
        return a.day - b.day;
      })
      .map(({ day, dateKey, ...item }) => item);
  }

  function handleAddItem() {
    if (activeSection === "entries" || activeSection === "todos" || activeSection === "lists") {
      if (activeSection === "entries") {
        createTemplateMode = false;
      }
      showNewItemInput = true;
      newItemName = "";
      queueMicrotask(() => newItemInput?.focus());
      return;
    }

    if (activeSection === "fragments") {
      onOpenDocument(createFragmentDraft());
      return;
    }

    if (activeSection === "calendar") {
      const selected = selectedCalendarDate ?? {
        year: calendarYear,
        month: calendarMonth,
        day: 1,
        key: toDateKey(calendarYear, calendarMonth, 1)
      };
      const monthLabel = new Date(selected.year, selected.month, selected.day).toLocaleString(undefined, {
        month: "short"
      });
      const label = `${monthLabel} ${selected.day} Note`;
      const item: SidePanelItem = {
        id: `calendar/${selected.key}/note-${Date.now()}`,
        label,
        initialContent: `# ${label}\n\nDate: ${selected.key}\n\nAdd your note...`
      };
      customCalendarEntries = [item, ...customCalendarEntries];
      onOpenDocument(item);
    }
  }

  function handleAddTemplate() {
    if (activeSection !== "entries") return;
    createTemplateMode = true;
    showNewItemInput = true;
    newItemName = "";
    queueMicrotask(() => newItemInput?.focus());
  }

  async function confirmNewItem() {
    const label = newItemName.trim();
    if (!label) {
      cancelNewItem();
      return;
    }
    showNewItemInput = false;
    newItemName = "";

    if (activeSection === "entries") {
      const isTemplate = createTemplateMode;
      const displayLabel = isTemplate
        ? label.endsWith("_template")
          ? label
          : `${label}_template`
        : label;
      const id = isTemplate ? `entries/template-draft-${Date.now()}` : `entries/draft-${Date.now()}`;
      const item = { id, label: displayLabel, initialContent: `# ${displayLabel}\n\n` };
      entriesStore.update((items) => [item, ...items]);
      onEditItem(item);
      createTemplateMode = false;
    } else if (activeSection === "todos") {
      try {
        const { meta, items: todoItems } = await createTodoListFromLabel(label);
        onOpenDocument({
          id: meta.id,
          label: meta.label,
          initialContent: serializeTodoList(meta.label, todoItems)
        });
      } catch (error) {
        const draft = createTodoListDraft();
        draft.meta.label = label;
        todoListsStore.update((lists) => [draft.meta, ...lists]);
        todosStore.update((lists) => ({ ...lists, [draft.meta.id]: draft.items }));
        onOpenDocument({
          id: draft.meta.id,
          label: draft.meta.label,
          initialContent: serializeTodoList(draft.meta.label, draft.items)
        });
      }
    } else if (activeSection === "lists") {
      try {
        const item = await createListFromLabel(label);
        onOpenDocument(item);
      } catch (error) {
        const item = createListDraft();
        item.label = label;
        item.initialContent = `# ${label}\n\n`;
        listsStore.update((items) => [item, ...items]);
        onOpenDocument(item);
      }
    }
  }

  function cancelNewItem() {
    showNewItemInput = false;
    newItemName = "";
    createTemplateMode = false;
  }

  function handleNewItemKeydown(event: KeyboardEvent) {
    if (event.key === "Enter") {
      event.preventDefault();
      confirmNewItem();
    } else if (event.key === "Escape") {
      cancelNewItem();
    }
  }

  $: panelTitle = sectionTitles[activeSection] ?? "Entries";
  $: todoDocuments = $todoListsStore.map(({ id, label }) => ({
    id,
    label,
    initialContent: serializeTodoList(label, $todosStore[id] ?? [])
  }));
  $: items = activeSection === "entries"
    ? $entriesStore
    : activeSection === "todos"
      ? todoDocuments
    : activeSection === "fragments"
      ? $fragmentsStore
      : activeSection === "lists"
        ? $listsStore
        : [];
  $: isCalendarSection = activeSection === "calendar";
  $: calendarEntries = [...customCalendarEntries, ...getCalendarEntries(calendarYear, calendarMonth)];
  $: showItemActions = activeSection === "entries" || activeSection === "todos" || activeSection === "lists" || activeSection === "fragments";
  $: entryItems = activeSection === "entries"
    ? $entriesStore.filter((item) => !item.id.startsWith("entries/template-draft-"))
    : [];
  $: templateDraftItems = activeSection === "entries"
    ? $entriesStore.filter((item) => item.id.startsWith("entries/template-draft-"))
    : [];
  $: allTemplateItems = [...templateDraftItems, ...templateItems];

  $: if (activeSection === "entries" && (!wasEntriesSection || templateRefreshToken !== lastTemplateRefreshToken)) {
    wasEntriesSection = true;
    lastTemplateRefreshToken = templateRefreshToken;
    void refreshTemplates();
  }

  $: if (activeSection !== "entries") {
    wasEntriesSection = false;
  }
</script>

<section class="side-panel" aria-label="Section panel">
  <header class="panel-header">
    <h2>{panelTitle}</h2>
    <div class="panel-header-actions">
      {#if activeSection === "entries"}
        <button type="button" class="panel-action" aria-label="Add template" title="Add template" on:click={handleAddTemplate}>
          <span class="material-symbols-outlined">palette</span>
        </button>
      {/if}
      <button type="button" class="panel-action" aria-label="Add item" title="Add item" on:click={handleAddItem}>
        <span class="material-symbols-outlined">add</span>
      </button>
    </div>
  </header>

  {#if isCalendarSection}
    <CalendarWidget
      onVisibleMonthChange={handleVisibleMonthChange}
      onSelectedDateChange={handleSelectedDateChange}
    />

    <div class="calendar-entries">
      <h3>{calendarMonthLabel} {calendarYear} Entries</h3>
      <ul class="panel-list">
        {#each calendarEntries as item}
          <li class:is-active={item.id === activeDocumentId}>
            <button
              type="button"
              class="item-label"
              on:click={() => onOpenDocument(item)}
            >
              {item.label}
            </button>
          </li>
        {/each}
      </ul>
    </div>
  {:else}
    <div class="panel-search">
      <span class="material-symbols-outlined">search</span>
      <input type="text" placeholder={`Search ${panelTitle.toLowerCase()}...`} />
    </div>

    {#if showNewItemInput}
      <div class="new-item-input">
        <input
          type="text"
          bind:this={newItemInput}
          bind:value={newItemName}
          placeholder={activeSection === "entries"
            ? createTemplateMode
              ? "Template name..."
              : "Entry name..."
            : activeSection === "todos"
              ? "Todo list name..."
              : "List name..."}
          on:keydown={handleNewItemKeydown}
          on:blur={confirmNewItem}
        />
      </div>
    {/if}

    {#if activeSection === "entries"}
      <div class="panel-subsection">
        <h3>Entries</h3>
        {#if $entriesBusyStore}
          <p class="section-copy">Loading entries...</p>
        {:else}
          <ul class="panel-list">
            {#each entryItems as item}
              <li class:is-active={item.id === activeDocumentId}>
                <button
                  type="button"
                  class="item-label"
                  on:click={() => onOpenDocument(item)}
                >
                  {item.label}
                </button>
                <div class="item-actions">
                  <button type="button" class="item-action" on:click|stopPropagation={() => onEditItem(item)} aria-label="Edit">
                    <span class="material-symbols-outlined">edit</span>
                  </button>
                  <button type="button" class="item-action item-action-danger" on:click|stopPropagation={() => onDeleteItem(item)} aria-label="Delete">
                    <span class="material-symbols-outlined">delete</span>
                  </button>
                </div>
              </li>
            {/each}
          </ul>
          {#if !entryItems.length}
            <p class="section-copy">No entries found.</p>
          {/if}
        {/if}
      </div>

      <div class="panel-subsection">
        <h3>Templates</h3>
        {#if templatesBusy}
          <p class="section-copy">Loading templates...</p>
        {:else}
          <ul class="panel-list">
            {#each allTemplateItems as item}
              <li class:is-active={item.id === activeDocumentId}>
                <button
                  type="button"
                  class="item-label"
                  on:click={() => onOpenDocument(item)}
                >
                  {item.label}
                </button>
                <div class="item-actions">
                  <button type="button" class="item-action" on:click|stopPropagation={() => onEditItem(item)} aria-label="Edit">
                    <span class="material-symbols-outlined">edit</span>
                  </button>
                  <button type="button" class="item-action item-action-danger" on:click|stopPropagation={() => onDeleteItem(item)} aria-label="Delete">
                    <span class="material-symbols-outlined">delete</span>
                  </button>
                </div>
              </li>
            {/each}
          </ul>
          {#if !allTemplateItems.length}
            <p class="section-copy">No templates found.</p>
          {/if}
        {/if}
        {#if templateError}
          <p class="template-error">{templateError}</p>
        {/if}
      </div>
    {:else}
      <ul class="panel-list">
        {#each items as item}
          <li class:is-active={item.id === activeDocumentId}>
            <button
              type="button"
              class="item-label"
              on:click={() => onOpenDocument(item)}
            >
              {item.label}
            </button>
            {#if showItemActions}
              <div class="item-actions">
                <button type="button" class="item-action" on:click|stopPropagation={() => onEditItem(item)} aria-label="Edit">
                  <span class="material-symbols-outlined">edit</span>
                </button>
                <button type="button" class="item-action item-action-danger" on:click|stopPropagation={() => onDeleteItem(item)} aria-label="Delete">
                  <span class="material-symbols-outlined">delete</span>
                </button>
              </div>
            {/if}
          </li>
        {/each}
      </ul>
    {/if}
  {/if}
</section>

<style>
  .side-panel {
    background: linear-gradient(180deg, var(--surface-2) 0%, var(--bg-panel) 100%);
    border-right: 1px solid var(--border-soft);
    padding: 16px 14px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
    overflow: hidden;
  }

  .panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .panel-header-actions {
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .panel-header h2 {
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--text-primary);
  }

  .panel-action {
    width: 28px;
    height: 28px;
    display: grid;
    place-items: center;
    border-radius: 6px;
    color: var(--text-muted);
    cursor: pointer;
    border: 1px solid transparent;
  }

  .panel-action:hover {
    background: var(--bg-hover);
    border-color: var(--border-soft);
    color: var(--text-primary);
  }

  .panel-action .material-symbols-outlined {
    font-size: 1.05rem;
  }

  .panel-search {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--surface-1);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 7px 9px;
  }

  .panel-search .material-symbols-outlined {
    color: var(--text-dim);
    font-size: 1rem;
  }

  .panel-search input {
    width: 100%;
    font-size: 0.84rem;
    color: var(--text-primary);
  }

  .panel-search input::placeholder {
    color: var(--text-dim);
  }

  .panel-list {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 0;
    overflow: auto;

    li {
      display: flex;
      align-items: center;
      border-radius: 7px;
      border: 1px solid transparent;

      &:hover {
        background: var(--bg-hover);
        border-color: var(--border-soft);
      }

      &.is-active {
        background: var(--bg-active);
        border-color: var(--border-strong);
      }
    }

    .item-label {
      flex: 1;
      min-width: 0;
      text-align: left;
      padding: 7px 9px;
      font-size: 0.84rem;
      color: var(--text-muted);
      cursor: pointer;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    li:hover .item-label,
    li.is-active .item-label {
      color: var(--text-primary);
    }

    .item-actions {
      display: none;
      flex-shrink: 0;
      align-items: center;
      gap: 2px;
      padding-right: 4px;
    }

    li:hover .item-actions,
    li.is-active .item-actions {
      display: flex;
    }

    .item-action {
      width: 24px;
      height: 24px;
      display: grid;
      place-items: center;
      border-radius: 4px;
      color: var(--text-dim);
      cursor: pointer;
      border: 1px solid transparent;

      &:hover {
        background: var(--surface-2);
        color: var(--text-primary);
        border-color: var(--border-soft);
      }

      &.item-action-danger:hover {
        color: #e06c75;
      }

      .material-symbols-outlined {
        font-size: 0.85rem;
      }
    }
  }

  .calendar-entries {
    margin-top: 2px;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .calendar-entries h3 {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
    letter-spacing: 0.01em;
  }

  .panel-subsection {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 0;
  }

  .panel-subsection h3 {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
    letter-spacing: 0.01em;
  }

  .section-copy {
    color: var(--text-dim);
    font-size: 0.78rem;
  }

  .template-error {
    color: #e74c3c;
    font-size: 0.78rem;
  }

  .new-item-input {
    padding: 0 2px;

    input {
      width: 100%;
      font-size: 0.84rem;
      color: var(--text-primary);
      background: var(--surface-1);
      border: 1px solid var(--border-strong);
      border-radius: 7px;
      padding: 7px 9px;
      outline: none;

      &:focus {
        border-color: var(--accent, #6b8afd);
      }

      &::placeholder {
        color: var(--text-dim);
      }
    }
  }
</style>
