"use client";

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

import type { MediaKind } from "@prisma/client";
import { Check, Link2, Search, Type, Upload } from "lucide-react";
import { useEffect, useId, useMemo, useRef, useState } from "react";

import type { MediaOption } from "@/lib/media";
import { cn } from "@/lib/utils";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";

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;
  fileLabel?: string;
  externalLabel?: string;
  libraryLabel?: string;
  accept?: string;
  allowExternal?: boolean;
  allowClear?: boolean;
  clearLabel?: string;
  emptyValue?: Partial<MediaFieldState>;
};

export function MediaFieldPicker({
  title,
  value,
  onChange,
  options,
  hasInitialValue = false,
  inputName,
  fileFieldName,
  fileLabel,
  externalLabel,
  libraryLabel,
  accept,
  allowExternal = true,
  allowClear = false,
  clearLabel = "Remove",
  emptyValue,
}: MediaFieldPickerProps) {
  const hiddenInputRef = useRef<HTMLInputElement | null>(null);
  const searchId = useId();
  const [libraryQuery, setLibraryQuery] = useState("");
  const modeOptions: Array<MediaFieldState["mode"]> = allowExternal
    ? ["upload", "external", "library"]
    : ["upload", "library"];
  const filteredOptions = options.filter((option) => option.kind === value.kind);
  const selectedOption = filteredOptions.find((option) => option.id === value.assetId) ?? null;
  const visibleLibraryOptions = useMemo(() => {
    const normalizedQuery = libraryQuery.trim().toLowerCase();

    if (!normalizedQuery) {
      return filteredOptions;
    }

    return filteredOptions.filter((option) => option.label.toLowerCase().includes(normalizedQuery));
  }, [filteredOptions, libraryQuery]);
  const resolvedLabel =
    value.mode === "library"
      ? selectedOption?.label ?? value.label
      : value.label;
  const serializedValue = JSON.stringify({
    mode: value.mode,
    assetId: value.assetId,
    url: value.url,
    label: resolvedLabel,
    kind: value.kind,
  });
  const previewUrl =
    value.isCleared
      ? ""
      : value.mode === "library"
        ? selectedOption?.url ?? ""
        : value.mode === "external"
          ? value.url
          : ""
  ;
  const hasCurrentValue =
    !value.isCleared &&
    ((value.mode === "library" && value.assetId.trim() !== "") ||
      (value.mode === "external" && value.url.trim() !== ""));
  const canClear = allowClear && (hasCurrentValue || (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 (
    <div className="space-y-3 rounded-lg border bg-card p-4 shadow-sm">
      <div className="space-y-2">
        <Label className="sr-only">{title}</Label>
        <div className="flex flex-wrap gap-2">
          {modeOptions.map((mode) => (
            <button
              key={mode}
              type="button"
              onClick={() =>
                onChange({
                  ...value,
                  mode,
                  assetId: mode === "library" ? value.assetId : "",
                  url: mode === "external" ? value.url : "",
                  isCleared: false,
                })
              }
              className={cn(
                "rounded-md border px-4 py-2 text-sm transition-colors",
                value.mode === mode
                  ? "border-input bg-primary text-primary-foreground"
                  : "border-input bg-background text-foreground/75 hover:bg-accent hover:text-accent-foreground",
              )}
            >
              {mode}
            </button>
          ))}
          {canClear ? (
            <button
              type="button"
              onClick={() =>
                onChange({
                  ...value,
                  mode: emptyValue?.mode ?? "upload",
                  assetId: emptyValue?.assetId ?? "",
                  url: emptyValue?.url ?? "",
                  label: emptyValue?.label ?? value.label,
                  isCleared: true,
                })
              }
              className="rounded-md border border-destructive/25 px-4 py-2 text-sm text-destructive transition-colors hover:bg-destructive/5"
            >
              {clearLabel}
            </button>
          ) : null}
        </div>
      </div>

      <input
        ref={hiddenInputRef}
        type="hidden"
        name={inputName}
        value={serializedValue}
      />

      {value.mode !== "library" ? (
        <div className="space-y-2">
          <Label className="sr-only">Label</Label>
          <div className="relative">
            <Type className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input
              value={value.label}
              onChange={(event) => onChange({ ...value, label: event.target.value, isCleared: false })}
              placeholder="Label"
              className="pl-9"
            />
          </div>
        </div>
      ) : null}

      {value.mode === "upload" ? (
        <div className="space-y-2">
          <Label className="sr-only">{fileLabel ?? fileFieldName}</Label>
          <div className="relative">
            <Upload className="pointer-events-none absolute left-3 top-1/2 z-10 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input name={fileFieldName} type="file" accept={accept} className="pl-9 file:mr-3" />
          </div>
        </div>
      ) : null}

      {value.mode === "external" ? (
        <div className="space-y-2">
          <Label className="sr-only">{externalLabel ?? "External URL"}</Label>
          <div className="relative">
            <Link2 className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input
              value={value.url}
              onChange={(event) => onChange({ ...value, url: event.target.value, isCleared: false })}
              placeholder={externalLabel ?? "External URL"}
              className="pl-9"
            />
          </div>
        </div>
      ) : null}

      {value.mode === "library" ? (
        <div className="space-y-3">
          <Label className="sr-only">{libraryLabel ?? "Media Library"}</Label>
          <div className="space-y-2 rounded-md border bg-card p-3">
            <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
                id={searchId}
                value={libraryQuery}
                onChange={(event) => setLibraryQuery(event.target.value)}
                className="pl-9"
                placeholder="Search media"
              />
            </div>

            <div className="max-h-64 space-y-2 overflow-y-auto">
              {visibleLibraryOptions.length > 0 ? (
                visibleLibraryOptions.map((option) => {
                  const isActive = option.id === value.assetId;

                  return (
                    <button
                      key={option.id}
                      type="button"
                      onClick={() =>
                        onChange({
                          ...value,
                          assetId: option.id,
                          label: option.label,
                          isCleared: false,
                        })
                      }
                      className={cn(
                        "flex w-full items-center gap-3 rounded-md border px-3 py-2 text-left transition-colors",
                        isActive
                          ? "border-input bg-accent/40"
                          : "border-input bg-background hover:bg-accent/20",
                      )}
                    >
                      {option.url ? (
                        <img src={option.url} alt={option.label} className="h-12 w-12 rounded-md object-cover" />
                      ) : (
                        <div className="h-12 w-12 rounded-md border border-border bg-background" />
                      )}
                      <div className="min-w-0 flex-1">
                        <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}
                    </button>
                  );
                })
              ) : (
                <div className="rounded-md border border-dashed border-input px-3 py-4 text-sm text-muted-foreground">
                  No media found.
                </div>
              )}
            </div>
          </div>
        </div>
      ) : null}

      {previewUrl ? (
        value.kind === "IMAGE" ? (
          <div className="overflow-hidden rounded-md border bg-card">
            <img src={previewUrl} alt={value.label || title} className="h-40 w-full object-cover" />
          </div>
        ) : (
          <div className="rounded-md border bg-card px-4 py-3 text-sm text-muted-foreground">
            {previewUrl}
          </div>
        )
      ) : null}
    </div>
  );
}
