"use client";

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

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

import { AppCard } from "@/components/ui/app-card";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
import type { AppLocale } from "@/lib/locale";
import type { MediaOption } from "@/lib/media";
import { cn } from "@/lib/utils";
import {
  PAGE_TITLE_TOKEN,
  SITE_NAME_TOKEN,
  type SiteSettings,
  type SiteSettingsMediaBindings,
} from "@/lib/site-settings";

type SiteSettingsFormProps = {
  action: (formData: FormData) => Promise<void>;
  initialSettings: SiteSettings;
  initialBindings: SiteSettingsMediaBindings;
  mediaOptions: MediaOption[];
};

type MediaFieldState = {
  mode: "upload" | "library";
  assetId: string;
  url: string;
  label: string;
  kind: MediaKind;
};

const localeFields: Array<{
  key: AppLocale;
  label: string;
  suffix: "Ar" | "En" | "De";
  sampleTitle: string;
}> = [
  {
    key: "ar",
    label: "Arabic",
    suffix: "Ar",
    sampleTitle: "Home",
  },
  {
    key: "en",
    label: "English",
    suffix: "En",
    sampleTitle: "About",
  },
  {
    key: "de",
    label: "Deutsch",
    suffix: "De",
    sampleTitle: "Portfolio",
  },
];

function createImageFieldState(
  assetId: string | null | undefined,
  url: string | null | undefined,
  label: string,
): MediaFieldState {
  if (assetId) {
    return {
      mode: "library",
      assetId,
      url: "",
      label,
      kind: MediaKind.IMAGE,
    };
  }

  return {
    mode: "upload",
    assetId: "",
    url: url ?? "",
    label,
    kind: MediaKind.IMAGE,
  };
}

function getMediaPreviewUrl(
  value: MediaFieldState,
  options: MediaOption[],
  fallbackUrl: string | null | undefined,
) {
  if (value.mode === "library") {
    return options.find((option) => option.id === value.assetId)?.url ?? fallbackUrl ?? "";
  }

  return fallbackUrl ?? "";
}

function buildPreviewTitle(
  titleTemplate: string,
  sampleTitle: string,
  siteName: string,
) {
  return titleTemplate.includes(PAGE_TITLE_TOKEN)
    ? titleTemplate
        .replace(PAGE_TITLE_TOKEN, sampleTitle)
        .replaceAll(SITE_NAME_TOKEN, siteName)
    : `${sampleTitle} | ${siteName}`;
}

function MediaLibraryModal({
  open,
  onOpenChange,
  options,
  selectedAssetId,
  onSelect,
  title,
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  options: MediaOption[];
  selectedAssetId: string;
  onSelect: (option: MediaOption) => void;
  title: string;
}) {
  const searchId = useId();
  const [query, setQuery] = useState("");
  const visibleOptions = useMemo(() => {
    const normalizedQuery = query.trim().toLowerCase();

    if (!normalizedQuery) {
      return options;
    }

    return options.filter((option) => option.label.toLowerCase().includes(normalizedQuery));
  }, [options, query]);

  useEffect(() => {
    if (!open) {
      setQuery("");
    }
  }, [open]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-h-[calc(100vh-1.5rem)] w-[calc(100vw-1rem)] max-w-4xl overflow-y-auto">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
          <DialogDescription>Bild aus der Media Library auswaehlen.</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
              id={searchId}
              value={query}
              onChange={(event) => setQuery(event.target.value)}
              className="pl-9"
              placeholder="Search media"
            />
          </div>

          <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
            {visibleOptions.length > 0 ? (
              visibleOptions.map((option) => {
                const isActive = option.id === selectedAssetId;

                return (
                  <button
                    key={option.id}
                    type="button"
                    onClick={() => {
                      onSelect(option);
                      onOpenChange(false);
                    }}
                    className={cn(
                      "overflow-hidden rounded-nested border text-left transition-colors",
                      isActive
                        ? "border-input bg-accent/30"
                        : "border-border/70 bg-background hover:bg-accent/10",
                    )}
                  >
                    <div className="aspect-[4/3] bg-muted/30">
                      {option.url ? (
                        <img src={option.url} alt={option.label} className="h-full w-full object-cover" />
                      ) : null}
                    </div>
                    <div className="flex items-center gap-3 p-3">
                      <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}
                    </div>
                  </button>
                );
              })
            ) : (
              <div className="col-span-full rounded-nested border border-dashed border-input px-4 py-8 text-sm text-muted-foreground">
                No media found.
              </div>
            )}
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}

function SiteSettingsMediaRow({
  title,
  value,
  onChange,
  options,
  inputName,
  fileFieldName,
  accept,
  clearLabel,
  fallbackUrl,
}: {
  title: string;
  value: MediaFieldState;
  onChange: (nextValue: MediaFieldState) => void;
  options: MediaOption[];
  inputName: string;
  fileFieldName: string;
  accept: string;
  clearLabel: string;
  fallbackUrl?: string | null;
}) {
  const [isLibraryOpen, setIsLibraryOpen] = useState(false);
  const hiddenInputRef = useRef<HTMLInputElement | null>(null);
  const fileInputId = useId();
  const previewUrl = getMediaPreviewUrl(value, options, fallbackUrl);
  const serializedValue = JSON.stringify({
    mode: value.mode,
    assetId: value.assetId,
    url: value.url,
    label: value.label,
    kind: value.kind,
  });

  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">
        <div className="grid gap-4 lg:grid-cols-[180px_minmax(0,1fr)]">
          <div className="space-y-2">
            <p className="text-sm font-semibold text-foreground">{title}</p>
            <div className="flex h-20 w-full items-center justify-center overflow-hidden rounded-nested border border-border/70 bg-muted/30">
              {previewUrl ? (
                <img src={previewUrl} alt={title} className="h-full w-full object-contain p-2" />
              ) : (
                <ImageIcon className="h-5 w-5 text-muted-foreground" />
              )}
            </div>
          </div>

          <div className="space-y-3">
            <input ref={hiddenInputRef} type="hidden" name={inputName} value={serializedValue} />

            <div className="grid gap-3 md:grid-cols-[minmax(0,1fr)_auto_auto]">
              <div className="relative">
                <Type className="pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
                <Input
                  value={value.label}
                  onChange={(event) => onChange({ ...value, label: event.target.value })}
                  placeholder="Label"
                  className="pl-8"
                />
              </div>

              <label
                htmlFor={fileInputId}
                className="inline-flex h-10 cursor-pointer items-center justify-center gap-2 rounded-nested border border-input bg-background px-4 text-sm transition-colors hover:bg-accent hover:text-accent-foreground"
              >
                <Upload className="h-4 w-4" />
                Upload
              </label>

              <Button type="button" variant="outline" onClick={() => setIsLibraryOpen(true)}>
                <ImageIcon className="h-4 w-4" />
                Library
              </Button>
            </div>

            <input
              id={fileInputId}
              name={fileFieldName}
              type="file"
              accept={accept}
              className="hidden"
              onChange={(event) => {
                const nextLabel = event.target.files?.[0]?.name.replace(/\.[^.]+$/, "") ?? value.label;

                onChange({
                  ...value,
                  mode: "upload",
                  assetId: "",
                  label: value.label.trim() ? value.label : nextLabel,
                });
              }}
            />

            <div className="flex flex-wrap items-center gap-2">
              <BadgeLike>{value.mode === "library" && value.assetId ? "Library selected" : "Upload mode"}</BadgeLike>
              {value.assetId ? (
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  className="h-8 px-2 text-destructive hover:bg-destructive/5 hover:text-destructive"
                  onClick={() =>
                    onChange({
                      ...value,
                      mode: "upload",
                      assetId: "",
                      url: "",
                    })
                  }
                >
                  {clearLabel}
                </Button>
              ) : null}
            </div>
          </div>
        </div>
      </AppCard>

      <MediaLibraryModal
        open={isLibraryOpen}
        onOpenChange={setIsLibraryOpen}
        options={options.filter((option) => option.kind === MediaKind.IMAGE)}
        selectedAssetId={value.assetId}
        title={title}
        onSelect={(option) =>
          onChange({
            ...value,
            mode: "library",
            assetId: option.id,
            url: "",
            label: option.label,
          })
        }
      />
    </>
  );
}

function BadgeLike({ children }: { children: string }) {
  return (
    <span className="inline-flex items-center rounded-full border border-border/70 bg-muted/30 px-2.5 py-1 text-xs text-muted-foreground">
      {children}
    </span>
  );
}

export function SiteSettingsForm({
  action,
  initialSettings,
  initialBindings,
  mediaOptions,
}: SiteSettingsFormProps) {
  const [settings, setSettings] = useState(initialSettings);
  const [siteLogoLight, setSiteLogoLight] = useState<MediaFieldState>(
    createImageFieldState(
      initialBindings.siteLogoLight?.assetId,
      initialBindings.siteLogoLight?.url,
      "Site Logo Light",
    ),
  );
  const [siteLogoDark, setSiteLogoDark] = useState<MediaFieldState>(
    createImageFieldState(
      initialBindings.siteLogoDark?.assetId,
      initialBindings.siteLogoDark?.url,
      "Site Logo Dark",
    ),
  );
  const [favicon, setFavicon] = useState<MediaFieldState>(
    createImageFieldState(
      initialBindings.favicon?.assetId,
      initialBindings.favicon?.url,
      "Favicon",
    ),
  );
  const [defaultOgImage, setDefaultOgImage] = useState<MediaFieldState>(
    createImageFieldState(
      initialBindings.defaultOgImage?.assetId,
      initialBindings.defaultOgImage?.url,
      "Default OG Image",
    ),
  );

  const siteLogoLightPreviewUrl = getMediaPreviewUrl(
    siteLogoLight,
    mediaOptions,
    initialBindings.siteLogoLight?.url,
  );
  const siteLogoDarkPreviewUrl = getMediaPreviewUrl(
    siteLogoDark,
    mediaOptions,
    initialBindings.siteLogoDark?.url,
  );
  const faviconPreviewUrl = getMediaPreviewUrl(favicon, mediaOptions, initialBindings.favicon?.url);
  const defaultOgImagePreviewUrl = getMediaPreviewUrl(
    defaultOgImage,
    mediaOptions,
    initialBindings.defaultOgImage?.url,
  );

  return (
    <form id="site-settings-form" action={action} className="space-y-6">
      <div className="grid gap-6 xl:grid-cols-[minmax(0,3fr)_minmax(300px,1fr)]">
        <div className="space-y-6">
          <section className="space-y-5">
            <div className="space-y-2">
              <h2 className="text-lg font-semibold text-foreground">Localized Titles And Copy</h2>
              <p className="text-sm text-muted-foreground">
                Nutze
                {" "}
                <code>{PAGE_TITLE_TOKEN}</code>
                {" "}
                und
                {" "}
                <code>{SITE_NAME_TOKEN}</code>
                {" "}
                fuer die globalen Titelvorlagen pro Sprache.
              </p>
            </div>

            <div className="grid gap-5 lg:grid-cols-3">
              {localeFields.map((locale) => (
                <AppCard key={locale.key} level={2} padding="sm" className="space-y-4">
                  <p className="text-sm font-semibold text-foreground">{locale.label}</p>

                  <div className="space-y-2">
                    <Label htmlFor={`siteName${locale.suffix}`} className="sr-only">Site Name</Label>
                    <div className="relative">
                      <Type className="pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
                      <Input
                        id={`siteName${locale.suffix}`}
                        name={`siteName${locale.suffix}`}
                        value={settings.locales[locale.key].siteName}
                        onChange={(event) =>
                          setSettings((current) => ({
                            ...current,
                            locales: {
                              ...current.locales,
                              [locale.key]: {
                                ...current.locales[locale.key],
                                siteName: event.target.value,
                              },
                            },
                          }))
                        }
                        placeholder="Site Name"
                        className="pl-8"
                      />
                    </div>
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor={`titleTemplate${locale.suffix}`} className="sr-only">Title Template</Label>
                    <div className="relative">
                      <Search className="pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
                      <Input
                        id={`titleTemplate${locale.suffix}`}
                        name={`titleTemplate${locale.suffix}`}
                        value={settings.locales[locale.key].titleTemplate}
                        onChange={(event) =>
                          setSettings((current) => ({
                            ...current,
                            locales: {
                              ...current.locales,
                              [locale.key]: {
                                ...current.locales[locale.key],
                                titleTemplate: event.target.value,
                              },
                            },
                          }))
                        }
                        placeholder="Title Template"
                        className="pl-8"
                      />
                    </div>
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor={`siteDescription${locale.suffix}`} className="sr-only">Site Description</Label>
                    <div className="relative">
                      <FileText className="pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
                      <Input
                        id={`siteDescription${locale.suffix}`}
                        name={`siteDescription${locale.suffix}`}
                        value={settings.locales[locale.key].siteDescription}
                        onChange={(event) =>
                          setSettings((current) => ({
                            ...current,
                            locales: {
                              ...current.locales,
                              [locale.key]: {
                                ...current.locales[locale.key],
                                siteDescription: event.target.value,
                              },
                            },
                          }))
                        }
                        placeholder="Site Description"
                        className="pl-8"
                      />
                    </div>
                  </div>

                  <div className="space-y-2">
                    <Label htmlFor={`subhead${locale.suffix}`} className="sr-only">Subhead</Label>
                    <div className="relative">
                      <Type className="pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
                      <Input
                        id={`subhead${locale.suffix}`}
                        name={`subhead${locale.suffix}`}
                        value={settings.locales[locale.key].subhead}
                        onChange={(event) =>
                          setSettings((current) => ({
                            ...current,
                            locales: {
                              ...current.locales,
                              [locale.key]: {
                                ...current.locales[locale.key],
                                subhead: event.target.value,
                              },
                            },
                          }))
                        }
                        placeholder="Subhead"
                        className="pl-8"
                      />
                    </div>
                  </div>
                </AppCard>
              ))}
            </div>
          </section>

          <section className="space-y-4">
            <h2 className="text-lg font-semibold text-foreground">Brand And Preview Images</h2>

            <SiteSettingsMediaRow
              title="Site Logo Light"
              value={siteLogoLight}
              onChange={setSiteLogoLight}
              options={mediaOptions}
              inputName="siteLogoLightMedia"
              fileFieldName="siteLogoLightFile"
              accept="image/*,.svg"
              clearLabel="Remove"
              fallbackUrl={initialBindings.siteLogoLight?.url}
            />

            <SiteSettingsMediaRow
              title="Site Logo Dark"
              value={siteLogoDark}
              onChange={setSiteLogoDark}
              options={mediaOptions}
              inputName="siteLogoDarkMedia"
              fileFieldName="siteLogoDarkFile"
              accept="image/*,.svg"
              clearLabel="Remove"
              fallbackUrl={initialBindings.siteLogoDark?.url}
            />

            <SiteSettingsMediaRow
              title="Favicon"
              value={favicon}
              onChange={setFavicon}
              options={mediaOptions}
              inputName="faviconMedia"
              fileFieldName="faviconFile"
              accept=".png,.svg,.ico,image/png,image/svg+xml,image/x-icon,image/vnd.microsoft.icon"
              clearLabel="Remove"
              fallbackUrl={initialBindings.favicon?.url}
            />

            <SiteSettingsMediaRow
              title="Default OG Image"
              value={defaultOgImage}
              onChange={setDefaultOgImage}
              options={mediaOptions}
              inputName="defaultOgImageMedia"
              fileFieldName="defaultOgImageFile"
              accept="image/*,.svg"
              clearLabel="Remove"
              fallbackUrl={initialBindings.defaultOgImage?.url}
            />
          </section>
        </div>

        <div className="xl:sticky xl:top-6 xl:self-start">
          <section className="space-y-4">
            <h2 className="text-lg font-semibold text-foreground">Preview</h2>

            <AppCard level={2} padding="sm" className="space-y-2">
              <p className="text-sm font-semibold text-foreground">Search Result</p>
              <div className="rounded-nested border border-border/70 bg-background p-3">
                <div className="flex items-center gap-3">
                  {faviconPreviewUrl ? (
                    <img src={faviconPreviewUrl} alt="Favicon" className="h-4 w-4 rounded-sm object-cover" />
                  ) : (
                    <div className="flex h-4 w-4 items-center justify-center rounded-sm border border-border/70 bg-muted/40">
                      <Type className="h-3 w-3 text-muted-foreground" />
                    </div>
                  )}
                  <p className="text-sm font-medium text-brand-primary">
                    {buildPreviewTitle(
                      settings.locales.de.titleTemplate,
                      "About",
                      settings.locales.de.siteName,
                    )}
                  </p>
                </div>
                <p className="mt-2 text-xs text-muted-foreground">
                  {settings.locales.de.siteDescription || "No description"}
                </p>
              </div>
            </AppCard>

            <AppCard level={2} padding="sm" className="space-y-2">
              <p className="text-sm font-semibold text-foreground">Brand Assets</p>
              <div className="grid gap-3 sm:grid-cols-2">
                <AppCard level={1} padding="sm">
                  <p className="mb-2 text-xs font-medium uppercase tracking-[0.12em] text-muted-foreground">Light</p>
                  {siteLogoLightPreviewUrl ? (
                    <img
                      src={siteLogoLightPreviewUrl}
                      alt="Site Logo Light"
                      className="h-10 w-full object-contain"
                    />
                  ) : (
                    <div className="flex h-10 items-center text-sm text-muted-foreground">No logo selected</div>
                  )}
                </AppCard>

                <div className="rounded-nested border border-border/70 bg-slate-950 p-3">
                  <p className="mb-2 text-xs font-medium uppercase tracking-[0.12em] text-white/55">Dark</p>
                  {siteLogoDarkPreviewUrl ? (
                    <img
                      src={siteLogoDarkPreviewUrl}
                      alt="Site Logo Dark"
                      className="h-10 w-full object-contain"
                    />
                  ) : (
                    <div className="flex h-10 items-center text-sm text-white/60">No logo selected</div>
                  )}
                </div>
              </div>
            </AppCard>

            <AppCard level={2} padding="sm" className="space-y-2">
              <p className="text-sm font-semibold text-foreground">Social Preview</p>
              <div className="overflow-hidden rounded-nested border border-border/70 bg-background">
                {defaultOgImagePreviewUrl ? (
                  <img src={defaultOgImagePreviewUrl} alt="Default OG" className="h-24 w-full object-cover" />
                ) : (
                  <div className="flex h-24 items-center justify-center bg-muted/30 text-sm text-muted-foreground">
                    No OG image selected
                  </div>
                )}
                <div className="space-y-1.5 p-3">
                  <p className="text-sm font-medium text-foreground">
                    {buildPreviewTitle(
                      settings.locales.en.titleTemplate,
                      "Portfolio",
                      settings.locales.en.siteName,
                    )}
                  </p>
                  <p className="text-xs text-muted-foreground">
                    {settings.locales.en.siteDescription || "No description"}
                  </p>
                </div>
              </div>
            </AppCard>

            <AppCard level={2} padding="sm" className="space-y-2">
              <p className="text-sm font-semibold text-foreground">Locale Summary</p>
              <div className="rounded-nested border border-border/70 bg-background">
                <Table>
                  <TableBody>
                    {localeFields.map((locale) => (
                      <TableRow key={locale.key}>
                        <TableCell className="w-24 font-medium">{locale.label}</TableCell>
                        <TableCell>
                          <p className="text-sm font-medium text-foreground">
                            {buildPreviewTitle(
                              settings.locales[locale.key].titleTemplate,
                              locale.sampleTitle,
                              settings.locales[locale.key].siteName,
                            )}
                          </p>
                          <p className="mt-1 text-xs text-muted-foreground">
                            {settings.locales[locale.key].subhead || "No subhead"}
                          </p>
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
            </AppCard>
          </section>
        </div>
      </div>
      <div className="flex justify-end">
        <Button type="submit">Save Settings</Button>
      </div>
    </form>
  );
}
