<script lang="ts">
  import { Button } from "$lib/components/ui/button";
  import { Input } from "$lib/components/ui/input";
  import { Label } from "$lib/components/ui/label";
  import { enhance } from "$app/forms";
  import { POCKETBASE_BASE_URL } from "$lib/pocketbase";
  import { UOM_OPTIONS, CATAGORY_OPTIONS, SUB_CATAGORY_OPTIONS } from "$lib/constants/items";
  import type { StackqItem } from "$lib/types/items";

  const COLLECTION = "Stackq_Items";
  function itemImageUrl(recordId: string, filename: string): string {
    return `${POCKETBASE_BASE_URL}/api/files/${COLLECTION}/${recordId}/${filename}`;
  }

  let {
    item = null,
    itemsForParent = [],
    action,
    submitLabel,
    error,
    onSuccess,
  }: {
    item?: StackqItem | null;
    itemsForParent?: { id: string; Item: string; SKU: string }[];
    action: string;
    submitLabel: string;
    error?: string | null;
    onSuccess?: () => void;
  } = $props();

  const isEdit = $derived(!!item);
  const parentOptions = $derived(
    item ? itemsForParent.filter((p) => p.id !== item!.id) : itemsForParent
  );
  const defaultItem = $derived(item?.Item ?? "");
  const defaultSku = $derived(item?.SKU ?? "");
  const defaultDesc = $derived(item?.Description ?? "");
  const defaultUom = $derived(item?.UOM ?? "");
  const defaultCost = $derived(item?.Cost != null ? String(item.Cost) : "");
  const defaultVendor = $derived(item?.Vendor ?? "");
  const defaultCat = $derived(Array.isArray(item?.Catagory) ? item!.Catagory[0] : item?.Catagory ?? "");
  const defaultSub = $derived(Array.isArray(item?.Sub_Catagory) ? item!.Sub_Catagory[0] : item?.Sub_Catagory ?? "");
  const defaultParent = $derived(item?.Parent ?? "");
  const defaultHasParent = $derived(!!item?.Has_Parent);
  const defaultStock = $derived(!!item?.Stock);

  let skuValue = $state("");
  let showScanner = $state(false);
  let scanError = $state<string | null>(null);
  let videoEl = $state<HTMLVideoElement | undefined>(undefined);
  let stream: MediaStream | null = null;
  let scanRAF = 0;

  $effect(() => {
    skuValue = defaultSku;
  });

  async function ensureBarcodeDetector(): Promise<boolean> {
    if (typeof globalThis === "undefined" || "BarcodeDetector" in globalThis) return true;
    try {
      const mod = await import("barcode-detector-api-polyfill");
      (globalThis as unknown as { BarcodeDetector: typeof BarcodeDetector }).BarcodeDetector =
        mod.BarcodeDetector;
      return true;
    } catch {
      return false;
    }
  }

  async function startScan() {
    scanError = null;
    const hasDetector = await ensureBarcodeDetector();
    if (!hasDetector) {
      scanError = "Failed to load barcode scanner. Try again or use Chrome/Edge.";
      showScanner = true;
      return;
    }
    try {
      stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: "environment", width: { ideal: 1280 }, height: { ideal: 720 } },
      });
      showScanner = true;
    } catch (e) {
      scanError = e instanceof Error ? e.message : "Could not access camera.";
      showScanner = true;
    }
  }

  $effect(() => {
    if (!showScanner || !stream || !videoEl) return;
    videoEl.srcObject = stream;
    videoEl.play().then(() => scanLoop()).catch(() => {});
    return () => {
      if (videoEl.srcObject) videoEl.srcObject = null;
    };
  });

  const SCAN_INTERVAL_MS = 300;

  function scanLoop() {
    if (!showScanner || !videoEl || !("BarcodeDetector" in globalThis)) return;
    const detector = new (globalThis as unknown as { BarcodeDetector: typeof BarcodeDetector }).BarcodeDetector();
    let lastScan = 0;
    async function detect() {
      if (!showScanner || !videoEl) return;
      if (videoEl.readyState < 2) {
        scanRAF = requestAnimationFrame(detect);
        return;
      }
      const now = Date.now();
      if (now - lastScan >= SCAN_INTERVAL_MS) {
        lastScan = now;
        try {
          const barcodes = await detector.detect(videoEl);
          if (barcodes.length > 0) {
            skuValue = barcodes[0].rawValue;
            stopScan();
            return;
          }
        } catch {
          // ignore frame errors
        }
      }
      scanRAF = requestAnimationFrame(detect);
    }
    detect();
  }

  function stopScan() {
    showScanner = false;
    scanError = null;
    if (scanRAF) {
      cancelAnimationFrame(scanRAF);
      scanRAF = 0;
    }
    if (stream) {
      stream.getTracks().forEach((t) => t.stop());
      stream = null;
    }
    if (videoEl && videoEl.srcObject) {
      videoEl.srcObject = null;
    }
  }
</script>

<form
  method="POST"
  action={action}
  enctype="multipart/form-data"
  use:enhance={() => async ({ update, result }) => {
    await update();
    if (result.type === "success" && result.data?.success) {
      onSuccess?.();
    }
  }}
  class="flex flex-col gap-4"
>
  {#if isEdit}
    <input type="hidden" name="id" value={item!.id} />
  {/if}

  <div class="grid grid-cols-2 gap-4">
    <div class="space-y-2">
      <Label for="Item">Item</Label>
      <Input id="Item" name="Item" value={defaultItem} required />
    </div>
    <div class="space-y-2">
      <Label for="SKU">SKU</Label>
      <div class="flex gap-2">
        <Input id="SKU" name="SKU" bind:value={skuValue} class="flex-1" />
        <Button type="button" variant="outline" onclick={startScan} title="Scan barcode">Scan</Button>
      </div>
    </div>
  </div>

  {#if showScanner}
    <div
      class="bg-background/95 fixed inset-0 z-50 flex flex-col items-center justify-center gap-4 p-4 backdrop-blur-sm"
      role="dialog"
      aria-label="Scan barcode"
    >
      <div class="flex w-full max-w-sm flex-col gap-2">
        {#if scanError}
          <p class="text-destructive text-sm">{scanError}</p>
        {:else}
          <video
            bind:this={videoEl}
            class="border-input w-full rounded-lg border"
            muted
            playsinline
          ></video>
        {/if}
        <div class="flex gap-2">
          <Button type="button" variant="outline" class="flex-1" onclick={stopScan}>
            Cancel
          </Button>
        </div>
      </div>
    </div>
  {/if}

  <div class="space-y-2">
    <Label for="Description">Description</Label>
    <Input id="Description" name="Description" value={defaultDesc} />
  </div>

  <div class="space-y-2">
    <Label for="Image">Image</Label>
    {#if isEdit && item?.Image}
      <div class="flex flex-wrap items-center gap-3">
        <img
          src={itemImageUrl(item!.id, item!.Image)}
          alt=""
          class="size-20 rounded border object-cover"
        />
        <span class="text-muted-foreground text-sm">Replace:</span>
      </div>
    {/if}
    <Input id="Image" name="Image" type="file" accept="image/*" />
  </div>

  <div class="grid grid-cols-2 gap-4">
    <div class="space-y-2">
      <Label for="UOM">UOM</Label>
      <select
        id="UOM"
        name="UOM"
        class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
      >
        <option value="">—</option>
        {#each UOM_OPTIONS as o}
          <option value={o} selected={defaultUom === o}>{o}</option>
        {/each}
      </select>
    </div>
    <div class="space-y-2">
      <Label for="Cost">Cost</Label>
      <Input id="Cost" name="Cost" type="number" step="any" value={defaultCost} />
    </div>
  </div>

  <div class="space-y-2">
    <Label for="Vendor">Vendor</Label>
    <Input id="Vendor" name="Vendor" value={defaultVendor} />
  </div>

  <div class="grid grid-cols-2 gap-4">
    <div class="space-y-2">
      <Label for="Catagory">Catagory</Label>
      <select
        id="Catagory"
        name="Catagory"
        class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
      >
        <option value="">—</option>
        {#each CATAGORY_OPTIONS as o}
          <option value={o} selected={defaultCat === o}>{o}</option>
        {/each}
      </select>
    </div>
    <div class="space-y-2">
      <Label for="Sub_Catagory">Sub_Catagory</Label>
      <select
        id="Sub_Catagory"
        name="Sub_Catagory"
        class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
      >
        <option value="">—</option>
        {#each SUB_CATAGORY_OPTIONS as o}
          <option value={o} selected={defaultSub === o}>{o}</option>
        {/each}
      </select>
    </div>
  </div>

  <div class="space-y-2">
    <Label for="Parent">Parent</Label>
    <select
      id="Parent"
      name="Parent"
      class="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm shadow-xs"
    >
      <option value="">—</option>
      {#each parentOptions as p}
        <option value={p.id} selected={defaultParent === p.id}>
          {p.Item || p.SKU || p.id}
        </option>
      {/each}
    </select>
  </div>

  <div class="flex flex-wrap gap-6">
    <label class="flex items-center gap-2 text-sm">
      <input
        type="checkbox"
        name="Has_Parent"
        value="on"
        checked={defaultHasParent}
        class="border-input size-4 rounded"
      />
      Has Parent
    </label>
    <label class="flex items-center gap-2 text-sm">
      <input
        type="checkbox"
        name="Stock"
        value="on"
        checked={defaultStock}
        class="border-input size-4 rounded"
      />
      Stock
    </label>
  </div>

  {#if error}
    <p class="text-destructive text-sm">{error}</p>
  {/if}

  <div class="flex justify-end gap-2">
    <Button type="submit">{submitLabel}</Button>
  </div>
</form>
