<script lang="ts">
  import { Button } from "$lib/components/ui/button";
  import { Card, CardContent } from "$lib/components/ui/card";
  import * as Collapsible from "$lib/components/ui/collapsible";
  import { Input } from "$lib/components/ui/input";
  import { Label } from "$lib/components/ui/label";
  import { convertImageToWebP } from "$lib/convert-image-to-webp";
  import { POCKETBASE_BASE_URL } from "$lib/pocketbase";
  import { enhance } from "$app/forms";
  import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
  import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
  import type { StackqReceipt } from "$lib/types/receipts";
  import type { ReceiptLineItem } from "$lib/types/receipts";

  const COLLECTION = "Stackq_Receipts";
  const STATUS_OPTIONS = ["New", "Data Entered", "Reviewed", "Consolidated"] as const;
  const TYPE_OPTIONS = ["Purchase", "Gas"] as const;

  let { data, form }: { data: { receipt: StackqReceipt }; form?: { error?: string; form?: string } } = $props();

  const receipt = $derived(data?.receipt);

  const formData = $state<{ lineItems: ReceiptLineItem[]; tax: number; receiptTotal: number }>({
    lineItems: [{ item: "", description: "", quantity: 1, price: 0 }],
    tax: 0,
    receiptTotal: 0,
  });

  $effect(() => {
    const r = receipt;
    if (!r) return;
    const data = r.Data;
    const nextItems: ReceiptLineItem[] =
      data && typeof data === "object" && "lineItems" in data
        ? (() => {
            const arr = (data as { lineItems?: ReceiptLineItem[] }).lineItems;
            if (Array.isArray(arr) && arr.length > 0) {
              return arr.map((row) => ({
                item: String(row?.item ?? ""),
                description: String(row?.description ?? ""),
                quantity: Number(row?.quantity) || 0,
                price: Number(row?.price) || 0,
              }));
            }
            return [{ item: "", description: "", quantity: 1, price: 0 }];
          })()
        : [{ item: "", description: "", quantity: 1, price: 0 }];
    const nextTax =
      data && typeof data === "object" && "tax" in data
        ? (() => {
            const t = (data as { tax?: number }).tax;
            return typeof t === "number" && Number.isFinite(t) ? t : 0;
          })()
        : 0;
    const nextReceiptTotal =
      data && typeof data === "object" && "receiptTotal" in data
        ? (() => {
            const t = (data as { receiptTotal?: number }).receiptTotal;
            return typeof t === "number" && Number.isFinite(t) ? t : 0;
          })()
        : 0;
    formData.lineItems = nextItems;
    formData.tax = nextTax;
    formData.receiptTotal = nextReceiptTotal;
  });

  const lineItems = $derived(formData.lineItems);
  const tax = $derived(formData.tax);
  const receiptTotal = $derived(formData.receiptTotal);

  const subtotal = $derived(
    lineItems.reduce((sum, row) => sum + (Number(row.quantity) || 0) * (Number(row.price) || 0), 0)
  );
  const total = $derived(subtotal + (Number(tax) || 0));
  const totalDelta = $derived((Number(receiptTotal) || 0) - (Number(total) || 0));

  function imageUrl(r: StackqReceipt): string | null {
    const raw = r?.Image;
    if (raw == null || raw === "") return null;
    const filename = typeof raw === "string" ? raw : Array.isArray(raw) ? raw[0] : null;
    if (!filename) return null;
    return `/api/files/${COLLECTION}/${r!.id}/${encodeURIComponent(filename)}`;
  }

  const currentImageUrl = $derived(receipt?.Image ? imageUrl(receipt) : null);

  function formatDate(iso: string): string {
    try {
      return new Date(iso).toLocaleString(undefined, {
        dateStyle: "medium",
        timeStyle: "short",
      });
    } catch {
      return iso;
    }
  }

  function addLine() {
    formData.lineItems.push({ item: "", description: "", quantity: 1, price: 0 });
  }

  function removeLine(i: number) {
    formData.lineItems.splice(i, 1);
    if (formData.lineItems.length === 0) formData.lineItems.push({ item: "", description: "", quantity: 1, price: 0 });
  }

  function buildDataJson(): string {
    const data = {
      lineItems: formData.lineItems.map((row) => ({
        item: String(row.item ?? ""),
        description: String(row.description ?? ""),
        quantity: Number(row.quantity) || 0,
        price: Number(row.price) || 0,
      })),
      tax: Number(formData.tax) || 0,
      receiptTotal: Number(formData.receiptTotal) || 0,
    };
    return JSON.stringify(data);
  }

  let imageInputEl = $state<HTMLInputElement | null>(null);
  let imageFileName = $state<string | null>(null);
  let selectedImageFile = $state<File | null>(null);
  let imageError = $state(false);

  /** On small screens image is collapsed by default; on lg+ expanded. */
  let imageOpen = $state(false);
  let imageOpenInitialized = $state(false);
  $effect(() => {
    if (typeof window === "undefined" || imageOpenInitialized) return;
    imageOpenInitialized = true;
    const mq = window.matchMedia("(min-width: 1024px)");
    imageOpen = mq.matches;
  });

  async function onImageChange() {
    const input = imageInputEl;
    const file = input?.files?.[0] ?? null;
    if (!file || !file.type.startsWith("image/")) {
      selectedImageFile = null;
      imageFileName = null;
      return;
    }
    try {
      const webpFile = await convertImageToWebP(file);
      selectedImageFile = webpFile;
      imageFileName = webpFile.name;
    } catch {
      selectedImageFile = null;
      imageFileName = null;
      if (input) input.value = "";
    }
  }
  function imageLoadError() {
    imageError = true;
  }
  $effect(() => {
    if (receipt?.Image) imageError = false;
  });
</script>

<svelte:head>
  <title>Receipt {receipt?.Status ?? receipt?.id ?? "—"} – Stackq</title>
</svelte:head>

<main class="flex w-full max-w-full flex-col gap-6 px-4 py-6 sm:px-6 sm:py-8">
  <div class="flex items-center gap-3">
    <a href="/receipts" class="text-muted-foreground hover:text-foreground shrink-0 text-sm" title="Back to receipts">Back</a>
    <h1 class="text-xl font-semibold sm:text-2xl">Receipt</h1>
  </div>

  {#if receipt}
    {@const url = currentImageUrl}
    <div class="grid grid-cols-1 gap-6 lg:grid-cols-[1fr_1.2fr]">
      <Card class="h-fit w-full">
        <CardContent class="p-4">
          <Collapsible.Root bind:open={imageOpen} class="space-y-2">
            <div class="flex items-center justify-between gap-2 lg:hidden">
              <span class="text-muted-foreground text-sm font-medium">Receipt image</span>
              <Collapsible.Trigger
                class="inline-flex size-8 items-center justify-center rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground"
                type="button"
              >
                {#if imageOpen}
                  <ChevronUpIcon class="size-4" aria-hidden />
                {:else}
                  <ChevronDownIcon class="size-4" aria-hidden />
                {/if}
                <span class="sr-only">{imageOpen ? "Hide image" : "Show image"}</span>
              </Collapsible.Trigger>
            </div>
            <Collapsible.Content>
              {#if url}
                <div class="min-h-[200px] w-full rounded border bg-muted/20">
                  {#if imageError}
                    <div class="flex min-h-[200px] flex-col items-center justify-center gap-2 p-4 text-center text-sm">
                      <p class="text-muted-foreground">Image could not be loaded.</p>
                      <a href={url} download class="text-primary hover:underline text-sm">Download image</a>
                    </div>
                  {:else}
                    <img
                      src={url}
                      alt="Receipt"
                      class="h-auto w-full rounded object-contain"
                      loading="lazy"
                      onerror={imageLoadError}
                    />
                  {/if}
                </div>
              {:else}
                <p class="text-muted-foreground text-center text-sm">No image. Add one in the form and save.</p>
              {/if}
            </Collapsible.Content>
          </Collapsible.Root>
        </CardContent>
      </Card>

      <Card>
        <CardContent class="p-4">
          <form
            method="POST"
            action="?/update"
            enctype="multipart/form-data"
            use:enhance={({ formData: fd }) => {
              if (selectedImageFile) fd.set("Image", selectedImageFile);
              return async ({ update, result }) => {
                await update();
                if (result.type === "success" && (result.data as { success?: boolean } | undefined)?.success) {
                  selectedImageFile = null;
                  imageFileName = null;
                }
              };
            }}
            class="flex flex-col gap-4"
          >
            <input type="hidden" name="dataJson" value={buildDataJson()} />
            <div class="relative flex items-center gap-2">
              <input
                id="receipt-image-input"
                bind:this={imageInputEl}
                type="file"
                name="Image"
                accept="image/*"
                capture="environment"
                onchange={onImageChange}
                class="absolute opacity-0 w-0 h-0 overflow-hidden"
                tabindex="-1"
                aria-label={receipt.Image ? "Replace image" : "Add image"}
              />
              <label
                for="receipt-image-input"
                class="border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex h-8 cursor-pointer items-center justify-center rounded-md border px-3 text-sm font-medium shadow-xs transition-colors"
              >
                {receipt.Image ? "Replace image" : "Add image"}
              </label>
              {#if imageFileName}
                <span class="text-muted-foreground text-xs">New: {imageFileName}</span>
              {/if}
            </div>
            <div class="grid gap-4 sm:grid-cols-2">
              <div class="space-y-2">
                <Label for="Status">Status</Label>
                <select
                  id="Status"
                  name="Status"
                  class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
                >
                  {#each STATUS_OPTIONS as o}
                    <option value={o} selected={receipt.Status === o}>{o}</option>
                  {/each}
                </select>
              </div>
              <div class="space-y-2">
                <Label for="Type">Type</Label>
                <select
                  id="Type"
                  name="Type"
                  class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
                >
                  {#each TYPE_OPTIONS as o}
                    <option value={o} selected={receipt.Type === o}>{o}</option>
                  {/each}
                </select>
              </div>
            </div>

            <div class="space-y-2">
              <div class="flex items-center justify-between">
                <Label>Line items</Label>
                <Button type="button" variant="outline" size="sm" onclick={addLine}>Add line</Button>
              </div>
              <div class="overflow-x-auto">
                <table class="w-full text-sm">
                  <thead>
                    <tr class="border-b text-left text-muted-foreground">
                      <th class="pb-2 pr-2 font-medium">Item</th>
                      <th class="pb-2 pr-2 font-medium">Description</th>
                      <th class="w-20 pb-2 pr-2 font-medium">Qty</th>
                      <th class="w-24 pb-2 pr-2 font-medium">Price</th>
                      <th class="w-9 pb-2"></th>
                    </tr>
                  </thead>
                  <tbody>
                    {#each formData.lineItems as row, i}
                      <tr class="border-b">
                        <td class="py-1.5 pr-2">
                          <Input
                            type="text"
                            placeholder="Item"
                            class="h-8 text-sm"
                            bind:value={formData.lineItems[i].item}
                          />
                        </td>
                        <td class="py-1.5 pr-2">
                          <Input
                            type="text"
                            placeholder="Description"
                            class="h-8 text-sm"
                            bind:value={formData.lineItems[i].description}
                          />
                        </td>
                        <td class="py-1.5 pr-2">
                          <Input
                            type="number"
                            step="1"
                            class="h-8 text-sm"
                            bind:value={formData.lineItems[i].quantity}
                          />
                        </td>
                        <td class="py-1.5 pr-2">
                          <Input
                            type="number"
                            step="0.01"
                            class="h-8 text-sm"
                            bind:value={formData.lineItems[i].price}
                          />
                        </td>
                        <td class="py-1.5">
                          <Button
                            type="button"
                            variant="ghost"
                            size="sm"
                            class="text-destructive h-8 w-8 p-0"
                            onclick={() => removeLine(i)}
                            title="Remove line"
                          >
                            ×
                          </Button>
                        </td>
                      </tr>
                    {/each}
                  </tbody>
                </table>
              </div>
            </div>

            <div class="border-t pt-4">
              <div class="flex items-center gap-4">
                <div class="space-y-2">
                  <Label for="tax">Tax</Label>
                  <Input
                    id="tax"
                    type="number"
                    step="0.01"
                    class="w-28"
                    bind:value={formData.tax}
                  />
                </div>
                <div class="space-y-2">
                  <Label for="receiptTotal">Receipt total</Label>
                  <Input
                    id="receiptTotal"
                    type="number"
                    step="0.01"
                    class="w-28"
                    bind:value={formData.receiptTotal}
                  />
                </div>
              </div>
              <dl class="mt-4 space-y-1 text-sm">
                <div class="flex justify-between gap-4">
                  <dt class="text-muted-foreground">Subtotal</dt>
                  <dd>${subtotal.toFixed(2)}</dd>
                </div>
                <div class="flex justify-between gap-4">
                  <dt class="text-muted-foreground">Tax</dt>
                  <dd>${(Number(tax) || 0).toFixed(2)}</dd>
                </div>
                <div class="flex justify-between gap-4 border-t pt-2 font-medium">
                  <dt>Total</dt>
                  <dd>${total.toFixed(2)}</dd>
                </div>
                <div class="flex justify-between gap-4 pt-2">
                  <dt class="text-muted-foreground">Receipt total</dt>
                  <dd>${(Number(receiptTotal) || 0).toFixed(2)}</dd>
                </div>
                <div class="flex justify-between gap-4">
                  <dt class="text-muted-foreground">Diff</dt>
                  <dd class={Math.abs(totalDelta) < 0.01 ? "text-emerald-600" : "text-amber-600"}>
                    {totalDelta >= 0 ? "+" : ""}{totalDelta.toFixed(2)}
                  </dd>
                </div>
              </dl>
            </div>

            {#if form?.error && form?.form === "update"}
              <p class="text-destructive text-sm">{form.error}</p>
            {/if}

            <div class="flex flex-wrap gap-2 pt-2">
              <Button type="submit">Save</Button>
              <a href="/receipts">
                <Button type="button" variant="outline">Back to receipts</Button>
              </a>
            </div>
          </form>
        </CardContent>
      </Card>
    </div>

    <Card>
      <CardContent class="flex flex-row flex-wrap items-center justify-between gap-4 py-4">
        <p class="text-muted-foreground text-sm">
          User: {receipt.expand?.User?.name ?? receipt.expand?.User?.email ?? "—"} · Created {formatDate(receipt.created)} · Updated {formatDate(receipt.updated)}
        </p>
        <form
          method="POST"
          action="?/delete"
          onsubmit={(e) => {
            if (!confirm("Delete this receipt? This cannot be undone.")) {
              e.preventDefault();
            }
          }}
        >
          <Button type="submit" variant="destructive">Delete receipt</Button>
        </form>
      </CardContent>
    </Card>
  {:else}
    <Card>
      <CardContent class="py-8">
        <p class="text-muted-foreground text-center text-sm">Receipt not found.</p>
        <a href="/receipts" class="mt-4 flex justify-center">
          <Button variant="outline">Back to receipts</Button>
        </a>
      </CardContent>
    </Card>
  {/if}
</main>
