"use client";

/* eslint-disable @next/next/no-img-element */

import type { MediaKind } from "@prisma/client";
import { Check, ImageIcon, Search, Trash2 } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";

import { AppCard } from "@/components/ui/app-card";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { MediaOption } from "@/lib/media";
import { cn } from "@/lib/utils";

export type MediaFieldState = {
  mode: "upload" | "external" | "library";
  assetId: string;
  url: string;
  label: string;
  kind: MediaKind;
  isCleared?: boolean;
};

type MediaFieldPickerProps = {
  title: string;
  value: MediaFieldState;
  onChange: (nextValue: MediaFieldState) => void;
  options: MediaOption[];
  hasInitialValue?: boolean;
  inputName: string;
  fileFieldName: string;
  allowClear?: boolean;
  clearLabel?: string;
  emptyValue?: Partial<MediaFieldState>;
};

export function MediaFieldPicker({
  title,
  value,
  onChange,
  options,
  hasInitialValue = false,
  inputName,
  allowClear = false,
  clearLabel = "Remove",
  emptyValue,
}: MediaFieldPickerProps) {
  const hiddenInputRef = useRef<HTMLInputElement | null>(null);
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState("");
  const filteredOptions = options.filter((option) => option.kind === value.kind);
  const selectedOption = filteredOptions.find((option) => option.id === value.assetId) ?? null;
  const visibleOptions = useMemo(() => {
    const normalizedQuery = query.trim().toLowerCase();

    if (!normalizedQuery) {
      return filteredOptions;
    }

    return filteredOptions.filter((option) => option.label.toLowerCase().includes(normalizedQuery));
  }, [filteredOptions, query]);
  const serializedValue = JSON.stringify({
    mode: value.mode,
    assetId: value.assetId,
    url: value.url,
    label: value.label,
    kind: value.kind,
  });
  const canClear = allowClear && (Boolean(value.assetId) || (hasInitialValue && !value.isCleared));

  useEffect(() => {
    const hiddenInput = hiddenInputRef.current;

    if (!hiddenInput) {
      return;
    }

    hiddenInput.dispatchEvent(new Event("input", { bubbles: true }));
    hiddenInput.dispatchEvent(new Event("change", { bubbles: true }));
  }, [serializedValue]);

  return (
    <AppCard level={2} padding="sm" className="space-y-4">
      <input ref={hiddenInputRef} type="hidden" name={inputName} value={serializedValue} />

      <div className="flex items-start justify-between gap-4">
        <div className="space-y-1">
          <Label className="text-sm font-semibold text-foreground">{title}</Label>
          <p className="text-sm text-muted-foreground">
            Media must be selected from the
            {" "}
            Media Library
            .
          </p>
        </div>
        <div className="flex gap-2">
          <Button type="button" variant="outline" onClick={() => setOpen(true)}>
            <ImageIcon className="h-4 w-4" />
            Select from Media
          </Button>
          {canClear ? (
            <Button
              type="button"
              variant="ghost"
              className="text-destructive hover:text-destructive"
              onClick={() =>
                onChange({
                  ...value,
                  mode: emptyValue?.mode ?? "upload",
                  assetId: emptyValue?.assetId ?? "",
                  url: emptyValue?.url ?? "",
                  label: emptyValue?.label ?? "",
                  isCleared: true,
                })
              }
            >
              <Trash2 className="h-4 w-4" />
              {clearLabel}
            </Button>
          ) : null}
        </div>
      </div>

      <AppCard padding="sm" className="rounded-nested border-border/70">
        {selectedOption ? (
          <div className="flex items-center gap-4">
            <img
              src={selectedOption.url}
              alt={selectedOption.label}
              className="h-16 w-16 rounded-nested object-cover"
            />
            <div className="min-w-0">
              <p className="truncate text-sm font-medium text-foreground">{selectedOption.label}</p>
              <p className="truncate text-xs text-muted-foreground">{selectedOption.source}</p>
            </div>
          </div>
        ) : (
          <div className="rounded-nested border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground">
            No media selected.
          </div>
        )}
      </AppCard>

      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="max-w-4xl">
          <DialogHeader>
            <DialogTitle>{title}</DialogTitle>
            <DialogDescription>Select an existing item from the media library.</DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <div className="relative">
              <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                value={query}
                onChange={(event) => setQuery(event.target.value)}
                placeholder="Search media"
                className="pl-9"
              />
            </div>

            <div className="grid max-h-[55vh] gap-3 overflow-y-auto md:grid-cols-2 xl:grid-cols-3">
              {visibleOptions.map((option) => {
                const isActive = option.id === value.assetId;

                return (
                  <button
                    key={option.id}
                    type="button"
                    onClick={() => {
                      onChange({
                        ...value,
                        mode: "library",
                        assetId: option.id,
                        url: option.url,
                        label: option.label,
                        isCleared: false,
                      });
                      setOpen(false);
                    }}
                    className={cn(
                      "overflow-hidden rounded-surface border text-left transition-colors",
                      isActive
                        ? "border-input bg-accent/20"
                        : "border-border/70 bg-card hover:border-input hover:bg-accent/10",
                    )}
                  >
                    <img src={option.url} alt={option.label} className="h-40 w-full object-cover" />
                    <div className="flex items-center justify-between gap-3 p-4">
                      <div className="min-w-0">
                        <p className="truncate text-sm font-medium text-foreground">{option.label}</p>
                        <p className="truncate text-xs text-muted-foreground">{option.source}</p>
                      </div>
                      {isActive ? <Check className="h-4 w-4 text-brand-primary" /> : null}
                    </div>
                  </button>
                );
              })}
            </div>
          </div>

          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setOpen(false)}>
              Close
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </AppCard>
  );
}
