<script lang="ts">
  import { createQuery, useQueryClient } from "@tanstack/svelte-query";
  import {
    listPresets,
    createPreset,
    deletePreset,
    renamePreset,
    createPresetEntry,
    updatePresetEntry,
    deletePresetEntry,
  } from "$lib/api/presets";
  import { listProducts } from "$lib/api/products";
  import { createMealFromPreset } from "$lib/api/meals";
  import { today } from "$lib/utils/date";
  import { kcal, g } from "$lib/utils/format";
  import TopBar from "$lib/components/ui/TopBar.svelte";
  import Sheet from "$lib/components/ui/Sheet.svelte";
  import type { Preset, PresetEntry, Product } from "$lib/types/api";

  const queryClient = useQueryClient();

  // ── Search / filter ───────────────────────────────────────────────────────
  let q = $state("");
  let debouncedQ = $state("");
  let debounceTimer: ReturnType<typeof setTimeout>;

  function handleSearch(value: string) {
    q = value;
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(() => {
      debouncedQ = value;
    }, 300);
  }

  const presetsQuery = createQuery(() => ({
    queryKey: ["presets"],
    queryFn: () => listPresets(100),
  }));

  const filteredPresets = $derived(
    (presetsQuery.data ?? []).filter(
      (p) =>
        !debouncedQ || p.name.toLowerCase().includes(debouncedQ.toLowerCase()),
    ),
  );

  // ── Expand/collapse ───────────────────────────────────────────────────────
  let expandedId = $state<number | null>(null);

  function toggleExpand(preset: Preset) {
    expandedId = expandedId === preset.id ? null : preset.id;
  }

  // ── Add to today ──────────────────────────────────────────────────────────
  let addingId = $state<number | null>(null);
  let addedId = $state<number | null>(null);

  async function handleAddToToday(preset: Preset) {
    addingId = preset.id;
    try {
      await createMealFromPreset(today(), preset.id, preset.name);
      queryClient.invalidateQueries({ queryKey: ["diary", today()] });
      addedId = preset.id;
      setTimeout(() => {
        addedId = null;
      }, 1500);
    } finally {
      addingId = null;
    }
  }

  // ── Create preset ─────────────────────────────────────────────────────────
  let creating = $state<boolean>(false);
  let creatingName = $state("");
  let creatingSaving = $state(false);

  async function handleCreate() {
    creatingSaving = true;
    try {
      await createPreset(creatingName.trim());
      queryClient.invalidateQueries({ queryKey: ["presets"] });
      creating = false;
      creatingName = "";
    } finally {
      creatingSaving = false;
    }
  }

  // ── Delete preset ─────────────────────────────────────────────────────────
  let deletingId = $state<number | null>(null);

  async function handleDelete(preset: Preset) {
    if (!confirm(`Delete preset "${preset.name}"?`)) return;
    deletingId = preset.id;
    try {
      await deletePreset(preset.id);
      if (expandedId === preset.id) expandedId = null;
      queryClient.invalidateQueries({ queryKey: ["presets"] });
    } finally {
      deletingId = null;
    }
  }

  // ── Rename preset ─────────────────────────────────────────────────────────
  let renamePreset_: Preset | null = $state(null);
  let renameName = $state("");
  let renaming = $state(false);

  function openRename(preset: Preset) {
    renamePreset_ = preset;
    renameName = preset.name;
  }

  async function handleRename(e: SubmitEvent) {
    e.preventDefault();
    if (!renamePreset_ || !renameName.trim()) return;
    renaming = true;
    try {
      await renamePreset(renamePreset_.id, renameName.trim());
      queryClient.invalidateQueries({ queryKey: ["presets"] });
      renamePreset_ = null;
    } finally {
      renaming = false;
    }
  }

  // ── Edit entry grams ──────────────────────────────────────────────────────
  let editingEntry = $state<{ presetId: number; entry: PresetEntry } | null>(
    null,
  );
  let editGrams = $state(0);
  let editSaving = $state(false);
  let editGramsInput = $state<HTMLInputElement | null>(null);

  function openEditEntry(presetId: number, entry: PresetEntry) {
    editingEntry = { presetId, entry };
    editGrams = entry.grams;
  }

  async function handleEditEntry(e: SubmitEvent) {
    e.preventDefault();
    if (!editingEntry) return;
    editSaving = true;
    try {
      await updatePresetEntry(
        editingEntry.presetId,
        editingEntry.entry.id,
        editGrams,
      );
      queryClient.invalidateQueries({ queryKey: ["presets"] });
      editingEntry = null;
    } finally {
      editSaving = false;
    }
  }

  // ── Delete entry ──────────────────────────────────────────────────────────
  async function handleDeleteEntry(presetId: number, entryId: number) {
    await deletePresetEntry(presetId, entryId);
    queryClient.invalidateQueries({ queryKey: ["presets"] });
  }

  // ── Add entry to preset ───────────────────────────────────────────────────
  let addEntryPresetId = $state<number | null>(null);
  let productQ = $state("");
  let productDebouncedQ = $state("");
  let productDebounceTimer: ReturnType<typeof setTimeout>;
  let selectedProduct = $state<Product | null>(null);
  let addGrams = $state(100);
  let addSaving = $state(false);
  let addGramsInput = $state<HTMLInputElement | null>(null);

  function openAddEntry(presetId: number) {
    addEntryPresetId = presetId;
    productQ = "";
    productDebouncedQ = "";
    selectedProduct = null;
    addGrams = 100;
  }

  function handleProductSearch(v: string) {
    productQ = v;
    clearTimeout(productDebounceTimer);
    productDebounceTimer = setTimeout(() => {
      productDebouncedQ = v;
    }, 300);
  }

  const productsQuery = createQuery(() => ({
    queryKey: ["products", productDebouncedQ],
    queryFn: () => listProducts(productDebouncedQ, 30),
    enabled: addEntryPresetId !== null,
    staleTime: 30_000,
  }));

  async function handleAddEntry(e: SubmitEvent) {
    e.preventDefault();
    if (!addEntryPresetId || !selectedProduct) return;
    addSaving = true;
    try {
      await createPresetEntry(addEntryPresetId, selectedProduct.id, addGrams);
      queryClient.invalidateQueries({ queryKey: ["presets"] });
      addEntryPresetId = null;
    } finally {
      addSaving = false;
    }
  }
</script>

<div class="flex flex-col h-screen">
  <TopBar title="Presets" back="/diary/{today()}" />

  <!-- Search -->
  <div class="px-4 py-3 border-b border-zinc-800 bg-zinc-950">
    <div class="relative">
      <svg
        class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-zinc-500"
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          stroke-width="2"
          d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
        />
      </svg>
      <input
        type="search"
        placeholder="Search presets…"
        value={q}
        oninput={(e) => handleSearch(e.currentTarget.value)}
        class="w-full bg-zinc-900 border border-zinc-700 rounded-xl pl-9 pr-4 py-2.5 text-sm text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-green-500 transition-colors"
      />
    </div>
  </div>

  <main class="flex-1 overflow-y-auto">
    {#if presetsQuery.isPending}
      <div class="space-y-2 p-4">
        {#each Array(5) as _}
          <div class="h-16 bg-zinc-900 rounded-xl animate-pulse"></div>
        {/each}
      </div>
    {:else if presetsQuery.isError}
      <p class="text-center text-zinc-500 mt-16">Could not load presets</p>
    {:else if !filteredPresets.length}
      <div class="text-center text-zinc-500 mt-16 px-6">
        <p>No presets yet</p>
        <p class="text-sm mt-1">Save a meal as preset from the diary view or</p>
      </div>
      <button
        onclick={() => (creating = true)}
        class="w-full rounded-xl py-4 text-green-500 hover:text-green-300 transition-colors text-sm font-medium"
      >
        Add preset
      </button>
    {:else}
      <ul class="divide-y divide-zinc-800/50">
        {#each filteredPresets as preset (preset.id)}
          <li>
            <!-- Preset header row -->
            <div class="flex items-center gap-2 px-4 py-3">
              <!-- Expand toggle + name -->
              <button
                onclick={() => toggleExpand(preset)}
                class="flex-1 flex items-center gap-2 text-left min-w-0"
              >
                <svg
                  class="w-4 h-4 text-zinc-500 shrink-0 transition-transform {expandedId ===
                  preset.id
                    ? ''
                    : '-rotate-90'}"
                  fill="none"
                  stroke="currentColor"
                  viewBox="0 0 24 24"
                >
                  <path
                    stroke-linecap="round"
                    stroke-linejoin="round"
                    stroke-width="2"
                    d="M19 9l-7 7-7-7"
                  />
                </svg>
                <div class="min-w-0">
                  <p class="font-medium truncate">{preset.name}</p>
                  <p class="text-xs text-zinc-500 mt-0.5">
                    {kcal(preset.calories)} kcal · P {g(preset.protein)}g · C {g(
                      preset.carb,
                    )}g · F {g(preset.fat)}g
                  </p>
                </div>
              </button>

              <!-- Action buttons -->
              <div class="flex items-center gap-1 shrink-0">
                <!-- Add to today -->
                <button
                  onclick={() => handleAddToToday(preset)}
                  disabled={addingId === preset.id}
                  class="flex items-center gap-1 px-2.5 py-1.5 rounded-lg text-xs font-medium transition-colors
										{addedId === preset.id
                    ? 'bg-green-600/20 text-green-400'
                    : 'bg-zinc-800 hover:bg-zinc-700 text-zinc-300 disabled:opacity-50'}"
                >
                  {#if addingId === preset.id}
                    <svg
                      class="w-3 h-3 animate-spin"
                      fill="none"
                      stroke="currentColor"
                      viewBox="0 0 24 24"
                    >
                      <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
                      />
                    </svg>
                  {:else if addedId === preset.id}
                    <svg
                      class="w-3 h-3"
                      fill="none"
                      stroke="currentColor"
                      viewBox="0 0 24 24"
                    >
                      <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M5 13l4 4L19 7"
                      />
                    </svg>
                    Added
                  {:else}
                    <svg
                      class="w-3 h-3"
                      fill="none"
                      stroke="currentColor"
                      viewBox="0 0 24 24"
                    >
                      <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M12 4v16m8-8H4"
                      />
                    </svg>
                    Today
                  {/if}
                </button>

                <!-- Rename -->
                <button
                  onclick={() => openRename(preset)}
                  class="w-8 h-8 flex items-center justify-center rounded-full text-zinc-500 hover:text-blue-400 hover:bg-blue-400/10 transition-colors"
                  aria-label="Rename preset"
                >
                  <svg
                    class="w-4 h-4"
                    fill="none"
                    stroke="currentColor"
                    viewBox="0 0 24 24"
                  >
                    <path
                      stroke-linecap="round"
                      stroke-linejoin="round"
                      stroke-width="2"
                      d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
                    />
                  </svg>
                </button>

                <!-- Delete -->
                <button
                  onclick={() => handleDelete(preset)}
                  disabled={deletingId === preset.id}
                  class="w-8 h-8 flex items-center justify-center rounded-full text-zinc-600 hover:text-red-400 hover:bg-red-400/10 disabled:opacity-30 transition-colors"
                  aria-label="Delete preset"
                >
                  <svg
                    class="w-4 h-4"
                    fill="none"
                    stroke="currentColor"
                    viewBox="0 0 24 24"
                  >
                    <path
                      stroke-linecap="round"
                      stroke-linejoin="round"
                      stroke-width="2"
                      d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
                    />
                  </svg>
                </button>
              </div>
            </div>

            <!-- Expanded entries -->
            {#if expandedId === preset.id}
              <div class="px-4 pb-3 border-t border-zinc-800/60">
                {#if preset.entries.length === 0}
                  <p class="text-sm text-zinc-600 py-3 text-center">
                    No entries yet
                  </p>
                {:else}
                  <ul class="divide-y divide-zinc-800/50">
                    {#each preset.entries as entry (entry.id)}
                      <li class="flex items-center justify-between py-2.5">
                        <button
                          onclick={() => openEditEntry(preset.id, entry)}
                          class="flex-1 text-left min-w-0 group"
                        >
                          <p class="text-sm font-medium truncate">
                            {entry.product.name}
                          </p>
                          <p class="text-xs text-zinc-500">
                            {entry.grams}g · {kcal(entry.calories)} kcal
                          </p>
                        </button>
                        <button
                          onclick={() => handleDeleteEntry(preset.id, entry.id)}
                          class="w-7 h-7 flex items-center justify-center rounded-full text-zinc-600 hover:text-red-400 hover:bg-red-400/10 transition-colors ml-2 shrink-0"
                          aria-label="Delete entry"
                        >
                          <svg
                            class="w-4 h-4"
                            fill="none"
                            stroke="currentColor"
                            viewBox="0 0 24 24"
                          >
                            <path
                              stroke-linecap="round"
                              stroke-linejoin="round"
                              stroke-width="2"
                              d="M6 18L18 6M6 6l12 12"
                            />
                          </svg>
                        </button>
                      </li>
                    {/each}
                  </ul>
                {/if}

                <!-- Add entry button -->
                <button
                  onclick={() => openAddEntry(preset.id)}
                  class="mt-2 flex items-center gap-1.5 text-xs font-medium text-zinc-500 hover:text-green-400 transition-colors"
                >
                  <svg
                    class="w-3.5 h-3.5"
                    fill="none"
                    stroke="currentColor"
                    viewBox="0 0 24 24"
                  >
                    <path
                      stroke-linecap="round"
                      stroke-linejoin="round"
                      stroke-width="2.5"
                      d="M12 4v16m8-8H4"
                    />
                  </svg>
                  Add food
                </button>
              </div>
            {/if}
          </li>
        {/each}
        <li>
          <button
            onclick={() => (creating = true)}
            class="w-full rounded-xl py-4 text-zinc-500 hover:text-zinc-300 transition-colors text-sm font-medium"
          >
            + Add preset
          </button>
        </li>
      </ul>
    {/if}
  </main>
</div>

<!-- Create preset sheet -->
<Sheet
  open={creating === true}
  onclose={() => {
    creating = false;
    creatingName = "";
  }}
  title="Create new preset"
>
  <form onsubmit={handleCreate} class="space-y-4">
    <input
      type="text"
      bind:value={creatingName}
      required
      autofocus
      class="w-full bg-zinc-800 border border-zinc-700 rounded-xl px-4 py-3 text-zinc-100 focus:outline-none focus:border-green-500 transition-colors"
    />
    <button
      type="submit"
      disabled={creatingSaving || !creatingName.trim()}
      class="w-full bg-green-600 hover:bg-green-500 disabled:opacity-50 rounded-xl py-3 font-semibold transition-colors"
    >
      {creatingSaving ? "Saving…" : "Save"}
    </button>
  </form>
</Sheet>

<!-- Rename preset sheet -->
<Sheet
  open={renamePreset_ !== null}
  onclose={() => (renamePreset_ = null)}
  title="Rename preset"
>
  <form onsubmit={handleRename} class="space-y-4">
    <input
      type="text"
      bind:value={renameName}
      required
      autofocus
      class="w-full bg-zinc-800 border border-zinc-700 rounded-xl px-4 py-3 text-zinc-100 focus:outline-none focus:border-green-500 transition-colors"
    />
    <button
      type="submit"
      disabled={renaming || !renameName.trim()}
      class="w-full bg-green-600 hover:bg-green-500 disabled:opacity-50 rounded-xl py-3 font-semibold transition-colors"
    >
      {renaming ? "Saving…" : "Save"}
    </button>
  </form>
</Sheet>

<!-- Edit entry grams sheet -->
<Sheet
  open={editingEntry !== null}
  onclose={() => (editingEntry = null)}
  title="Edit entry"
>
  {#if editingEntry}
    <form onsubmit={handleEditEntry} class="space-y-4">
      <p class="text-sm text-zinc-400">{editingEntry.entry.product.name}</p>
      <div>
        <label class="block text-sm text-zinc-400 mb-2">Grams</label>
        <div class="flex items-center gap-3">
          <button
            type="button"
            onpointerdown={(e) => e.preventDefault()}
            onclick={() => {
              editGrams = Math.max(1, editGrams - 10);
            }}
            class="w-11 h-11 rounded-xl bg-zinc-800 hover:bg-zinc-700 transition-colors text-lg font-medium flex items-center justify-center"
            >−</button
          >
          <input
            bind:this={editGramsInput}
            type="number"
            bind:value={editGrams}
            min="1"
            autofocus
            inputmode="decimal"
            onfocus={(e) => e.currentTarget.select()}
            class="flex-1 bg-zinc-800 border border-zinc-700 rounded-xl px-4 py-2.5 text-center text-xl font-semibold focus:outline-none focus:border-green-500 transition-colors"
          />
          <button
            type="button"
            onpointerdown={(e) => e.preventDefault()}
            onclick={() => {
              editGrams = editGrams + 10;
            }}
            class="w-11 h-11 rounded-xl bg-zinc-800 hover:bg-zinc-700 transition-colors text-lg font-medium flex items-center justify-center"
            >+</button
          >
        </div>
      </div>
      <button
        type="submit"
        disabled={editSaving || editGrams < 1}
        class="w-full bg-green-600 hover:bg-green-500 disabled:opacity-50 rounded-xl py-3 font-semibold transition-colors"
      >
        {editSaving ? "Saving…" : "Save"}
      </button>
    </form>
  {/if}
</Sheet>

<!-- Add entry to preset sheet -->
<Sheet
  open={addEntryPresetId !== null}
  onclose={() => {
    addEntryPresetId = null;
    selectedProduct = null;
  }}
  title="Add food to preset"
>
  {#if addEntryPresetId !== null}
    {#if selectedProduct === null}
      <!-- Product search -->
      <div class="space-y-3">
        <input
          type="search"
          placeholder="Search foods…"
          value={productQ}
          oninput={(e) => handleProductSearch(e.currentTarget.value)}
          autofocus
          class="w-full bg-zinc-800 border border-zinc-700 rounded-xl px-4 py-2.5 text-sm text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-green-500 transition-colors"
        />
        {#if productsQuery.isPending && productDebouncedQ}
          <p class="text-sm text-zinc-500 text-center py-4">Searching…</p>
        {:else}
          <ul
            class="max-h-64 overflow-y-auto divide-y divide-zinc-800/50 -mx-4"
          >
            {#each productsQuery.data ?? [] as product (product.id)}
              <li>
                <button
                  onclick={() => {
                    selectedProduct = product;
                    addGrams = 100;
                  }}
                  class="w-full flex items-center justify-between px-4 py-3 hover:bg-zinc-800 transition-colors text-left"
                >
                  <div class="min-w-0">
                    <p class="text-sm font-medium truncate capitalize">
                      {product.name}
                    </p>
                    <p class="text-xs text-zinc-500">
                      {kcal(product.calories)} kcal · P {g(product.protein)}g ·
                      C {g(product.carb)}g · F {g(product.fat)}g
                      <span class="text-zinc-600">/ 100g</span>
                    </p>
                  </div>
                </button>
              </li>
            {/each}
          </ul>
        {/if}
      </div>
    {:else}
      <!-- Grams input -->
      <form onsubmit={handleAddEntry} class="space-y-4">
        <div>
          <p class="text-sm font-medium capitalize mb-0.5">
            {selectedProduct.name}
          </p>
          <p class="text-xs text-zinc-500">
            {kcal(selectedProduct.calories)} kcal / 100g
          </p>
        </div>
        <div>
          <label class="block text-sm text-zinc-400 mb-2">Grams</label>
          <div class="flex items-center gap-3">
            <button
              type="button"
              onpointerdown={(e) => e.preventDefault()}
              onclick={() => {
                addGrams = Math.max(1, addGrams - 10);
              }}
              class="w-11 h-11 rounded-xl bg-zinc-800 hover:bg-zinc-700 transition-colors text-lg font-medium flex items-center justify-center"
              >−</button
            >
            <input
              bind:this={addGramsInput}
              type="number"
              bind:value={addGrams}
              min="1"
              autofocus
              inputmode="decimal"
              onfocus={(e) => e.currentTarget.select()}
              class="flex-1 bg-zinc-800 border border-zinc-700 rounded-xl px-4 py-2.5 text-center text-xl font-semibold focus:outline-none focus:border-green-500 transition-colors"
            />
            <button
              type="button"
              onpointerdown={(e) => e.preventDefault()}
              onclick={() => {
                addGrams = addGrams + 10;
              }}
              class="w-11 h-11 rounded-xl bg-zinc-800 hover:bg-zinc-700 transition-colors text-lg font-medium flex items-center justify-center"
              >+</button
            >
          </div>
        </div>
        <div class="flex gap-2">
          <button
            type="button"
            onclick={() => (selectedProduct = null)}
            class="flex-1 bg-zinc-800 hover:bg-zinc-700 rounded-xl py-3 text-sm font-medium transition-colors"
          >
            Back
          </button>
          <button
            type="submit"
            disabled={addSaving || addGrams < 1}
            class="flex-1 bg-green-600 hover:bg-green-500 disabled:opacity-50 rounded-xl py-3 font-semibold transition-colors"
          >
            {addSaving ? "Adding…" : "Add"}
          </button>
        </div>
      </form>
    {/if}
  {/if}
</Sheet>
