"use client";

import { FormEvent, useState } from "react";
import { Ellipsis, Loader2, Plus, Trash2 } from "lucide-react";
import {
  archiveBanner,
  createBanner,
  createCategory,
  deleteBrand,
  deleteCategory,
  upsertBrand,
  updateBrand,
  updateCategory,
  updateBanner,
} from "@/lib/actions/catalog";
import { ImageUploadInput } from "@/app/admin/dashboard/inventory/components/product-form/ImageUploadInput";
import { Button } from "@/components/ui/button";
import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  AlertDialog,
  AlertDialogClose,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

type CatalogItem = {
  id: string;
  name?: string;
  title?: string;
  slug?: string;
  logo?: string | null;
  image?: string | null;
  description?: string | null;
  link?: string | null;
  type?: "SLIDER" | "BOTTOM";
  sortOrder?: number;
};

type Props = {
  categories: CatalogItem[];
  brands: CatalogItem[];
  banners: CatalogItem[];
};
type BannerType = "SLIDER" | "BOTTOM";
type Feedback = { kind: "success" | "error"; text: string } | null;

function FeedbackMessage({ feedback }: { feedback: Feedback }) {
  if (!feedback) return null;
  return (
    <div
      role={feedback.kind === "error" ? "alert" : "status"}
      className={
        feedback.kind === "error"
          ? "rounded-xl border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive"
          : "rounded-xl border border-primary/20 bg-primary/10 px-4 py-3 text-sm"
      }
    >
      {feedback.text}
    </div>
  );
}

function BannerDialog({
  type,
  banner,
  open,
  onOpenChange,
  onSaved,
}: {
  type: BannerType;
  banner?: CatalogItem;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onSaved: (banner: CatalogItem, editing: boolean) => void;
}) {
  const editing = Boolean(banner);
  const [title, setTitle] = useState(banner?.title ?? "");
  const [description, setDescription] = useState(banner?.description ?? "");
  const [link, setLink] = useState(banner?.link ?? "");
  const [image, setImage] = useState(banner?.image ?? null);
  const [sortOrder, setSortOrder] = useState(String(banner?.sortOrder ?? 0));
  const [feedback, setFeedback] = useState<Feedback>(null);
  const [saving, setSaving] = useState(false);

  function reset(nextOpen: boolean) {
    if (!nextOpen) {
      setTitle(banner?.title ?? "");
      setDescription(banner?.description ?? "");
      setLink(banner?.link ?? "");
      setImage(banner?.image ?? null);
      setSortOrder(String(banner?.sortOrder ?? 0));
      setFeedback(null);
    }
    onOpenChange(nextOpen);
  }

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!title.trim() || !image) {
      setFeedback({
        kind: "error",
        text: "A title and banner image are required.",
      });
      return;
    }
    if (link && !/^https?:\/\//i.test(link)) {
      setFeedback({
        kind: "error",
        text: "Links must start with http:// or https://.",
      });
      return;
    }
    setSaving(true);
    setFeedback(null);
    const input = {
      title,
      description,
      link,
      image,
      type,
      sortOrder: Number(sortOrder) || 0,
    };
    const result = editing
      ? await updateBanner(banner!.id, input)
      : await createBanner(input);
    setSaving(false);
    if (!result.ok) {
      setFeedback({
        kind: "error",
        text: result.error ?? "The banner could not be saved.",
      });
      return;
    }
    onSaved(result.data as CatalogItem, editing);
    onOpenChange(false);
  }

  return (
    <Dialog open={open} onOpenChange={reset}>
      <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-xl">
        <DialogHeader>
          <DialogTitle>
            {editing ? "Edit" : "Add"} {type === "BOTTOM" ? "bottom" : "slider"}{" "}
            banner
          </DialogTitle>
          <DialogDescription>
            Add the storefront artwork and details for this{" "}
            {type === "BOTTOM" ? "bottom" : "slider"} banner.
          </DialogDescription>
        </DialogHeader>
        <form className="flex flex-col gap-4" onSubmit={handleSubmit}>
          <div className="flex flex-col gap-2">
            <Label htmlFor={`${type}-title`}>Title</Label>
            <Input
              id={`${type}-title`}
              value={title}
              onChange={(event) => setTitle(event.target.value)}
              required
            />
          </div>
          <div className="flex flex-col gap-2">
            <Label htmlFor={`${type}-description`}>Description</Label>
            <Textarea
              id={`${type}-description`}
              value={description}
              onChange={(event) => setDescription(event.target.value)}
              placeholder="Optional supporting text"
            />
          </div>
          <div className="grid gap-4 sm:grid-cols-[1fr_120px]">
            <div className="flex flex-col gap-2">
              <Label htmlFor={`${type}-link`}>Destination link</Label>
              <Input
                id={`${type}-link`}
                type="url"
                value={link}
                onChange={(event) => setLink(event.target.value)}
                placeholder="https://..."
              />
            </div>
            <div className="flex flex-col gap-2">
              <Label htmlFor={`${type}-order`}>Display order</Label>
              <Input
                id={`${type}-order`}
                type="number"
                min="0"
                value={sortOrder}
                onChange={(event) => setSortOrder(event.target.value)}
              />
            </div>
          </div>
          <div className="flex flex-col gap-2">
            <Label>Banner image</Label>
            <ImageUploadInput
              value={image}
              onChange={setImage}
              folder="banners"
              label="Banner image"
              disabled={saving}
            />
          </div>
          <FeedbackMessage feedback={feedback} />
          <DialogFooter>
            <Button
              type="button"
              variant="outline"
              onClick={() => reset(false)}
              disabled={saving}
            >
              Cancel
            </Button>
            <Button type="submit" disabled={saving || !image}>
              {saving && (
                <Loader2 className="animate-spin" data-icon="inline-start" />
              )}
              {saving
                ? "Saving..."
                : editing
                  ? "Save changes"
                  : "Create banner"}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}

function DeleteDialog({
  item,
  open,
  onOpenChange,
  onConfirm,
}: {
  item?: CatalogItem;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onConfirm: () => void;
}) {
  return (
    <AlertDialog open={open} onOpenChange={onOpenChange}>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>
            Delete {item?.title ?? item?.name}?
          </AlertDialogTitle>
          <AlertDialogDescription>
            This action removes the record from the active catalog. It cannot be
            undone from this page.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogClose render={<Button variant="outline" />}>
            Cancel
          </AlertDialogClose>
          <AlertDialogClose
            render={<Button variant="destructive" onClick={onConfirm} />}
          >
            Delete
          </AlertDialogClose>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  );
}

function BannerSection({
  type,
  banners,
  onChange,
  onFeedback,
}: {
  type: BannerType;
  banners: CatalogItem[];
  onChange: (next: CatalogItem[]) => void;
  onFeedback: (feedback: Feedback) => void;
}) {
  const [dialogOpen, setDialogOpen] = useState(false);
  const [editing, setEditing] = useState<CatalogItem>();
  const [deleting, setDeleting] = useState<CatalogItem>();
  const bottomFull = type === "BOTTOM" && banners.length >= 2;

  async function handleDelete() {
    if (!deleting) return;
    const result = await archiveBanner(deleting.id);
    setDeleting(undefined);
    if (!result.ok) {
      onFeedback({ kind: "error", text: result.error });
      return;
    }
    onChange(banners.filter((item) => item.id !== deleting.id));
    onFeedback({ kind: "success", text: result.message ?? "Banner deleted." });
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>
          {type === "BOTTOM" ? "Bottom banners" : "Slider banners"}
        </CardTitle>
        <CardDescription>
          {type === "BOTTOM"
            ? "Two promotional slots shown below the product sections."
            : "Rotating artwork displayed in the storefront hero."}
        </CardDescription>
        <CardAction>
          <div className="flex items-center gap-2">
            {type === "BOTTOM" && (
              <Badge variant={bottomFull ? "secondary" : "outline"}>
                {banners.length}/2
              </Badge>
            )}
            <Button
              size="sm"
              onClick={() => {
                setEditing(undefined);
                setDialogOpen(true);
              }}
              disabled={bottomFull}
            >
              <Plus data-icon="inline-start" /> Add banner
            </Button>
          </div>
        </CardAction>
      </CardHeader>
      <CardContent>
        {banners.length === 0 ? (
          <div className="rounded-xl border border-dashed px-6 py-10 text-center">
            <p className="font-medium">
              No {type === "BOTTOM" ? "bottom" : "slider"} banners yet
            </p>
            <p className="mt-1 text-sm text-muted-foreground">
              Create one to start managing this storefront area.
            </p>
          </div>
        ) : (
          <div className="grid gap-4 md:grid-cols-2">
            {banners.map((banner) => (
              <div
                key={banner.id}
                className="overflow-hidden rounded-xl border bg-muted/20"
              >
                <div className="aspect-[16/7] bg-muted">
                  {/* eslint-disable-next-line @next/next/no-img-element */}
                  <img
                    src={banner.image ?? ""}
                    alt={banner.title ?? "Banner"}
                    className="h-full w-full object-cover"
                  />
                </div>
                <div className="flex items-center justify-between gap-3 p-4">
                  <div className="min-w-0">
                    <p className="truncate font-medium">{banner.title}</p>
                    <p className="text-xs text-muted-foreground">
                      Order {banner.sortOrder ?? 0}
                    </p>
                  </div>
                  <DropdownMenu>
                    <DropdownMenuTrigger
                      render={
                        <Button
                          variant="ghost"
                          size="icon-sm"
                          aria-label={`Actions for ${banner.title}`}
                        />
                      }
                    >
                      <Ellipsis />
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end">
                      <DropdownMenuItem
                        onClick={() => {
                          setEditing(banner);
                          setDialogOpen(true);
                        }}
                      >
                        Edit banner
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        variant="destructive"
                        onClick={() => setDeleting(banner)}
                      >
                        <Trash2 /> Delete banner
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                </div>
              </div>
            ))}
          </div>
        )}
      </CardContent>
      <BannerDialog
        key={`${type}-${editing?.id ?? "new"}`}
        type={type}
        banner={editing}
        open={dialogOpen}
        onOpenChange={(open) => {
          setDialogOpen(open);
          if (!open) setEditing(undefined);
        }}
        onSaved={(next, isEditing) => {
          onChange(
            isEditing
              ? banners.map((item) => (item.id === next.id ? next : item))
              : [...banners, next],
          );
          onFeedback({
            kind: "success",
            text: isEditing ? "Banner updated." : "Banner created.",
          });
        }}
      />
      <DeleteDialog
        item={deleting}
        open={Boolean(deleting)}
        onOpenChange={(open) => {
          if (!open) setDeleting(undefined);
        }}
        onConfirm={handleDelete}
      />
    </Card>
  );
}

function NameDialog({
  item,
  kind,
  open,
  onOpenChange,
  onSaved,
}: {
  item?: CatalogItem;
  kind: "category" | "brand";
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onSaved: (item: CatalogItem) => void;
}) {
  const [name, setName] = useState(item?.name ?? "");
  const [slug, setSlug] = useState(item?.slug ?? "");
  const [image, setImage] = useState(item?.image ?? null);
  const [logo, setLogo] = useState(item?.logo ?? null);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState("");

  async function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!name.trim() || !item) return;
    setSaving(true);
    setError("");
    const result =
      kind === "category"
        ? await updateCategory(item.id, { name, slug, image })
        : await updateBrand(item.id, { name, logo: logo ?? undefined });
    setSaving(false);
    if (!result.ok) {
      setError(result.error ?? "The record could not be saved.");
      return;
    }
    onSaved(result.data as CatalogItem);
    onOpenChange(false);
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Edit {kind}</DialogTitle>
          <DialogDescription>Update the catalog details.</DialogDescription>
        </DialogHeader>
        <form className="flex flex-col gap-4" onSubmit={submit}>
          <div className="flex flex-col gap-2">
            <Label htmlFor={`${kind}-edit-name`}>Name</Label>
            <Input
              id={`${kind}-edit-name`}
              value={name}
              onChange={(event) => setName(event.target.value)}
              required
            />
          </div>
          {kind === "category" && (
            <>
              <div className="flex flex-col gap-2">
                <Label htmlFor="category-edit-slug">Slug</Label>
                <Input
                  id="category-edit-slug"
                  value={slug}
                  onChange={(event) => setSlug(event.target.value)}
                  required
                />
              </div>
              <div className="flex flex-col gap-2">
                <Label>Category image</Label>
                <ImageUploadInput
                  value={image}
                  onChange={setImage}
                  folder="categories"
                  label="Category image"
                  disabled={saving}
                />
              </div>
            </>
          )}
          {kind === "brand" && (
            <div className="flex flex-col gap-2">
              <Label>Brand logo</Label>
              <ImageUploadInput
                value={logo}
                onChange={setLogo}
                folder="brands"
                label="Brand logo"
                disabled={saving}
              />
            </div>
          )}
          {error && (
            <p role="alert" className="text-sm text-destructive">
              {error}
            </p>
          )}
          <DialogFooter>
            <Button
              type="button"
              variant="outline"
              onClick={() => onOpenChange(false)}
            >
              Cancel
            </Button>
            <Button type="submit" disabled={saving}>
              {saving ? "Saving..." : "Save changes"}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}

function BrandCreateForm({
  busy,
  onSaved,
  onFeedback,
}: {
  busy: boolean;
  onSaved: (brand: CatalogItem) => void;
  onFeedback: (feedback: Feedback) => void;
}) {
  const [name, setName] = useState("");
  const [logo, setLogo] = useState<string | null>(null);
  const [saving, setSaving] = useState(false);

  async function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!name.trim()) return;
    setSaving(true);
    const result = await upsertBrand({ name, logo: logo ?? undefined });
    setSaving(false);
    if (!result.ok) {
      onFeedback({
        kind: "error",
        text: result.error ?? "The brand could not be created.",
      });
      return;
    }
    if (result.data) onSaved(result.data as CatalogItem);
    setName("");
    setLogo(null);
    onFeedback({ kind: "success", text: result.message ?? "Brand added." });
  }

  return (
    <form
      className="flex flex-col gap-3 rounded-xl border border-dashed p-3"
      onSubmit={submit}
    >
      <div className="grid gap-3 sm:grid-cols-[1fr_auto]">
        <Input
          value={name}
          onChange={(event) => setName(event.target.value)}
          required
          placeholder="Brand name"
          aria-label="Brand name"
        />
        <Button type="submit" disabled={busy || saving}>
          {saving ? "Adding..." : "Add brand"}
        </Button>
      </div>
      <ImageUploadInput
        value={logo}
        onChange={setLogo}
        folder="brands"
        label="Brand logo"
        disabled={busy || saving}
      />
    </form>
  );
}

export default function CatalogClient({
  categories: initialCategories,
  brands: initialBrands,
  banners: initialBanners,
}: Props) {
  const [categories, setCategories] = useState(initialCategories);
  const [brands, setBrands] = useState(initialBrands);
  const [banners, setBanners] = useState(initialBanners);
  const [feedback, setFeedback] = useState<Feedback>(null);
  const [busy, setBusy] = useState(false);
  const [categoryImage, setCategoryImage] = useState<string | null>(null);
  const [editing, setEditing] = useState<{
    item: CatalogItem;
    kind: "category" | "brand";
  }>();
  const [deleting, setDeleting] = useState<CatalogItem>();

  async function addCategory(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = new FormData(event.currentTarget);
    setBusy(true);
    setFeedback(null);
    const result = await createCategory({
      name: String(form.get("name")),
      slug: String(form.get("slug") || ""),
      image: categoryImage ?? undefined,
    });
    setBusy(false);
    if (!result.ok) {
      setFeedback({
        kind: "error",
        text: result.error ?? "The record could not be deleted.",
      });
      return;
    }
    if (result.data)
      setCategories((items) => [...items, result.data as CatalogItem]);
    event.currentTarget.reset();
    setCategoryImage(null);
    setFeedback({
      kind: "success",
      text: result.message ?? "Category created.",
    });
  }

  async function deleteCatalogItem() {
    if (!deleting) return;
    setBusy(true);
    const isCategory = categories.some((item) => item.id === deleting.id);
    const result = isCategory
      ? await deleteCategory(deleting.id)
      : await deleteBrand(deleting.id);
    setBusy(false);
    setDeleting(undefined);
    if (!result.ok) {
      setFeedback({ kind: "error", text: result.error });
      return;
    }
    setCategories((items) => items.filter((item) => item.id !== deleting.id));
    setBrands((items) => items.filter((item) => item.id !== deleting.id));
    setFeedback({ kind: "success", text: result.message ?? "Deleted." });
  }

  return (
    <div className="flex flex-col gap-6">
      <div>
        <h1 className="text-2xl font-semibold tracking-tight">
          Catalog management
        </h1>
        <p className="mt-1 text-sm text-muted-foreground">
          Manage the categories, brands, and storefront banners used across the
          store.
        </p>
      </div>
      <FeedbackMessage feedback={feedback} />
      <div className="grid gap-6 xl:grid-cols-2">
        <Card>
          <CardHeader>
            <CardTitle>Categories</CardTitle>
            <CardDescription>
              Keep product navigation organized.
            </CardDescription>
          </CardHeader>
          <CardContent className="flex flex-col gap-4">
            <form
              className="grid gap-3 sm:grid-cols-[1fr_1fr_auto]"
              onSubmit={addCategory}
            >
              <Input
                name="name"
                required
                placeholder="Category name"
                aria-label="Category name"
              />
              <Input
                name="slug"
                placeholder="Slug"
                aria-label="Category slug"
                required
              />
              <ImageUploadInput
                value={categoryImage}
                onChange={setCategoryImage}
                folder="categories"
                label="Category image"
                disabled={busy}
                className="sm:col-span-2"
              />
              <Button type="submit" disabled={busy}>
                <Plus data-icon="inline-start" /> Add
              </Button>
            </form>
            <div className="divide-y rounded-xl border">
              {categories.length ? (
                categories.map((category) => (
                  <div
                    key={category.id}
                    className="flex items-center justify-between gap-3 px-3 py-3 text-sm"
                  >
                    <div className="min-w-0">
                      <p className="truncate font-medium">{category.name}</p>
                      <p className="truncate text-xs text-muted-foreground">
                        /{category.slug}
                      </p>
                    </div>
                    <div className="flex gap-1">
                      <Button
                        size="sm"
                        variant="ghost"
                        onClick={() =>
                          setEditing({ item: category, kind: "category" })
                        }
                      >
                        Edit
                      </Button>
                      <Button
                        size="sm"
                        variant="ghost"
                        className="text-destructive"
                        onClick={() => setDeleting(category)}
                      >
                        Delete
                      </Button>
                    </div>
                  </div>
                ))
              ) : (
                <p className="px-3 py-6 text-center text-sm text-muted-foreground">
                  No categories yet.
                </p>
              )}
            </div>
          </CardContent>
        </Card>
        <Card>
          <CardHeader>
            <CardTitle>Brands</CardTitle>
            <CardDescription>
              Manage the brands shown in the catalog.
            </CardDescription>
          </CardHeader>
          <CardContent className="flex flex-col gap-4">
            <BrandCreateForm
              busy={busy}
              onSaved={(brand) => setBrands((items) => [...items, brand])}
              onFeedback={setFeedback}
            />
            <div className="divide-y rounded-xl border">
              {brands.length ? (
                brands.map((brand) => (
                  <div
                    key={brand.id}
                    className="flex items-center justify-between gap-3 px-3 py-3 text-sm"
                  >
                    <span className="truncate font-medium">{brand.name}</span>
                    <div className="flex gap-1">
                      <Button
                        size="sm"
                        variant="ghost"
                        onClick={() =>
                          setEditing({ item: brand, kind: "brand" })
                        }
                      >
                        Edit
                      </Button>
                      <Button
                        size="sm"
                        variant="ghost"
                        className="text-destructive"
                        onClick={() => setDeleting(brand)}
                      >
                        Delete
                      </Button>
                    </div>
                  </div>
                ))
              ) : (
                <p className="px-3 py-6 text-center text-sm text-muted-foreground">
                  No brands yet.
                </p>
              )}
            </div>
          </CardContent>
          <CardFooter className="text-xs text-muted-foreground">
            Brand logos are managed from product and brand workflows.
          </CardFooter>
        </Card>
      </div>
      <div className="flex flex-col gap-6">
        <div>
          <h2 className="text-lg font-semibold">Banner management</h2>
          <p className="text-sm text-muted-foreground">
            Control the hero slider and the two promotional slots independently.
          </p>
        </div>
        <BannerSection
          type="SLIDER"
          banners={banners.filter(
            (banner) => (banner.type ?? "SLIDER") === "SLIDER",
          )}
          onChange={(next) =>
            setBanners((items) => [
              ...items.filter((item) => (item.type ?? "SLIDER") !== "SLIDER"),
              ...next,
            ])
          }
          onFeedback={setFeedback}
        />
        <BannerSection
          type="BOTTOM"
          banners={banners.filter((banner) => banner.type === "BOTTOM")}
          onChange={(next) =>
            setBanners((items) => [
              ...items.filter((item) => item.type !== "BOTTOM"),
              ...next,
            ])
          }
          onFeedback={setFeedback}
        />
      </div>
      <NameDialog
        key={editing ? `${editing.kind}-${editing.item.id}` : "name-dialog"}
        item={editing?.item}
        kind={editing?.kind ?? "category"}
        open={Boolean(editing)}
        onOpenChange={(open) => {
          if (!open) setEditing(undefined);
        }}
        onSaved={(next) => {
          if (editing?.kind === "category")
            setCategories((items) =>
              items.map((item) =>
                item.id === next.id ? { ...item, ...next } : item,
              ),
            );
          else
            setBrands((items) =>
              items.map((item) =>
                item.id === next.id ? { ...item, ...next } : item,
              ),
            );
          setFeedback({
            kind: "success",
            text: `${editing?.kind === "category" ? "Category" : "Brand"} updated.`,
          });
        }}
      />
      <DeleteDialog
        item={deleting}
        open={Boolean(deleting)}
        onOpenChange={(open) => {
          if (!open) setDeleting(undefined);
        }}
        onConfirm={deleteCatalogItem}
      />
    </div>
  );
}
