"use client";

import { useEffect, useState } from "react";

import { useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import { ImageIcon } from "lucide-react";
import { Controller, useForm } from "react-hook-form";
import { toast } from "sonner";

import type { FormSelectOption } from "@/app/dashboard/_components/form";
import { isApiSuccess } from "@/lib/api-messages";
import { dashboardCsrfHeader } from "@/lib/csrf.client";

import {
  FormPageHeader,
  FormPanel,
  FormSaveBar,
  FormSelect,
} from "@/app/dashboard/_components/form";
import { FormField } from "@/components/form/form-field";
import { ImagePreview } from "@/components/ui/image-preview";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";

import {
  BANNER_SITE_LABEL,
  BANNER_SITE_OPTIONS,
  BANNER_STATUS_FORM_OPTIONS,
} from "../constants";
import { ActiveReviewBadge } from "@/components/shared/status-pill";
import type { BannerRow } from "../schema";
import { BannerImageField } from "./image-field";
import {
  bannerFormDefaults,
  bannerFormSchema,
  type BannerFormValues,
} from "./schema";

const LIST_HREF = "/dashboard/master/banners";
const CREATE_SUBMIT_HREF = "/dashboard/master/banners/create/submit";
const UPDATE_SUBMIT_HREF = "/dashboard/master/banners/update";

type Props = {
  mode: "create" | "update";
  initial?: BannerRow;
  categoryOptions: FormSelectOption[];
};

function rowToFormValues(row: BannerRow): BannerFormValues {
  return {
    site: row.site,
    category_id: row.categoryId,
    priority: row.priority,
    content: row.content ?? "",
    status: row.status,
  };
}

function BannerPreview({
  values,
  imageUrl,
  categoryOptions,
}: {
  values: BannerFormValues;
  imageUrl?: string | null;
  categoryOptions: FormSelectOption[];
}) {
  const categoryLabel =
    categoryOptions.find((option) => option.value === values.category_id)?.label ?? "—";

  return (
    <div className="overflow-hidden rounded-xl border bg-card shadow-sm">
      <div className="border-b bg-linear-to-br from-violet-500/10 via-primary/5 to-card px-4 py-3">
        <div className="flex items-center justify-between gap-2">
          <ImageIcon className="size-5 text-primary" />
          <ActiveReviewBadge
            status={values.status}
            label={values.status === "A" ? "Active" : "Inactive"}
          />
        </div>
      </div>
      <div className="space-y-3 p-4">
        {imageUrl ? (
          <div className="flex justify-center rounded-lg border bg-black/90 p-2">
            <ImagePreview src={imageUrl} alt="Banner preview" className="max-h-20 max-w-full" />
          </div>
        ) : null}
        <dl className="space-y-1.5 text-xs">
          <div className="flex justify-between gap-2">
            <dt className="text-muted-foreground">Category</dt>
            <dd className="font-medium text-right">{categoryLabel}</dd>
          </div>
          <div className="flex justify-between gap-2">
            <dt className="text-muted-foreground">Site</dt>
            <dd className="font-medium">{BANNER_SITE_LABEL[values.site]}</dd>
          </div>
          <div className="flex justify-between gap-2">
            <dt className="text-muted-foreground">Priority</dt>
            <dd className="font-medium tabular-nums">{values.priority}</dd>
          </div>
        </dl>
        {values.content?.trim() ? (
          <p className="line-clamp-3 text-muted-foreground text-xs leading-relaxed">
            {values.content}
          </p>
        ) : null}
      </div>
    </div>
  );
}

export function BannerForm({ mode, initial, categoryOptions }: Props) {
  const router = useRouter();
  const [isSaving, setIsSaving] = useState(false);
  const [desktopFile, setDesktopFile] = useState<File | null>(null);
  const [mobileFile, setMobileFile] = useState<File | null>(null);
  const [desktopPreview, setDesktopPreview] = useState<string | null>(
    initial?.imageUrl ?? null,
  );
  const isUpdate = mode === "update";

  const form = useForm<BannerFormValues>({
    resolver: zodResolver(bannerFormSchema),
    defaultValues: initial ? rowToFormValues(initial) : bannerFormDefaults,
  });

  const watchValues = form.watch();
  const categoryId = form.watch("category_id");
  const isDiscountBanner = categoryId === "4";

  useEffect(() => {
    if (initial) {
      form.reset(rowToFormValues(initial));
      setDesktopPreview(initial.imageUrl ?? null);
    }
  }, [initial, form]);

  useEffect(() => {
    if (desktopFile) {
      const url = URL.createObjectURL(desktopFile);
      setDesktopPreview(url);
      return () => URL.revokeObjectURL(url);
    }
    setDesktopPreview(initial?.imageUrl ?? null);
  }, [desktopFile, initial?.imageUrl]);

  const onSubmit = form.handleSubmit(async (values) => {
    if (!isUpdate && !desktopFile) {
      toast.error("Image is required.");
      return;
    }

    setIsSaving(true);

    try {
      const formData = new FormData();
      formData.append("site", values.site);
      formData.append("category_id", values.category_id);
      formData.append("priority", String(values.priority));
      formData.append("status", values.status);
      formData.append("content", values.content ?? "");

      if (desktopFile) {
        formData.append("file_name", desktopFile, desktopFile.name);
      }
      if (mobileFile) {
        formData.append("mobile_image", mobileFile, mobileFile.name);
      }
      if (isUpdate && initial?.id != null) {
        formData.append("id", String(initial.id));
      }

      const response = await fetch(isUpdate ? UPDATE_SUBMIT_HREF : CREATE_SUBMIT_HREF, {
        method: "POST",
        body: formData,
        headers: dashboardCsrfHeader(),
      });

      const data = (await response.json().catch(() => null)) as {
        status?: string;
        message?: string;
      } | null;

      if (!response.ok || !data || !isApiSuccess(data)) {
        throw new Error(
          typeof data?.message === "string" && data.message.trim()
            ? data.message
            : isUpdate
              ? "Banner could not be updated."
              : "Banner could not be created.",
        );
      }

      toast.success(
        typeof data.message === "string" && data.message.trim()
          ? data.message
          : isUpdate
            ? "Banner updated"
            : "Banner created",
      );
      router.push(LIST_HREF);
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "Banner could not be saved.");
    } finally {
      setIsSaving(false);
    }
  });

  return (
    <form onSubmit={onSubmit} className="pb-4">
      <FormPageHeader
        backHref={LIST_HREF}
        breadcrumb={[
          { label: "Master" },
          { label: "Banners", href: LIST_HREF },
          { label: isUpdate ? "Update" : "Create new" },
        ]}
        titleIcon={<ImageIcon className="size-5 text-primary" />}
        title={isUpdate ? "Update banner" : "Create banner"}
        description="Site, category, desktop and mobile images, priority, content, and status."
      />

      <div className="grid gap-6 lg:grid-cols-[1fr_280px]">
        <div className="space-y-6">
          <FormPanel title="Placement">
            <div className="grid gap-5 sm:grid-cols-2">
              <Controller
                name="site"
                control={form.control}
                render={({ field, fieldState }) => (
                  <FormField
                    label="Site"
                    htmlFor="site"
                    required
                    error={fieldState.error}
                  >
                    <FormSelect
                      id="site"
                      value={field.value}
                      onChange={field.onChange}
                      placeholder="Select site"
                      options={BANNER_SITE_OPTIONS}
                    />
                  </FormField>
                )}
              />

              <Controller
                name="category_id"
                control={form.control}
                render={({ field, fieldState }) => (
                  <FormField
                    label="Category"
                    htmlFor="category_id"
                    required
                    error={fieldState.error}
                  >
                    <FormSelect
                      id="category_id"
                      value={field.value}
                      onChange={field.onChange}
                      placeholder="Please select"
                      options={categoryOptions}
                    />
                  </FormField>
                )}
              />
            </div>
          </FormPanel>

          <FormPanel title="Images">
            <div className="grid gap-6 sm:grid-cols-2">
              <BannerImageField
                id="file_name"
                label="Image"
                hint={initial?.fileName}
                value={desktopFile}
                existingUrl={initial?.imageUrl}
                required={!isUpdate}
                onChange={setDesktopFile}
              />

              {!isDiscountBanner ? (
                <BannerImageField
                  id="mobile_image"
                  label="Mobile image"
                  hint={initial?.mobileImage}
                  value={mobileFile}
                  onChange={setMobileFile}
                />
              ) : null}
            </div>
          </FormPanel>

          <FormPanel title="Details">
            <div className="grid gap-5 sm:grid-cols-2">
              <Controller
                name="priority"
                control={form.control}
                render={({ field, fieldState }) => (
                  <FormField
                    label="Priority"
                    htmlFor="priority"
                    description="Higher values appear first in carousel lists."
                    error={fieldState.error}
                  >
                    <Input
                      id="priority"
                      type="number"
                      min={0}
                      className="max-w-[120px] tabular-nums"
                      value={field.value}
                      onChange={(e) => {
                        const parsed = Number(e.target.value);
                        field.onChange(Number.isFinite(parsed) ? parsed : 0);
                      }}
                    />
                  </FormField>
                )}
              />

              <Controller
                name="status"
                control={form.control}
                render={({ field, fieldState }) => (
                  <FormField
                    label="Status"
                    htmlFor="status"
                    required
                    error={fieldState.error}
                  >
                    <FormSelect
                      id="status"
                      value={field.value}
                      onChange={field.onChange}
                      placeholder="Select status"
                      options={BANNER_STATUS_FORM_OPTIONS}
                    />
                  </FormField>
                )}
              />

              <Controller
                name="content"
                control={form.control}
                render={({ field, fieldState }) => (
                  <FormField
                    label="Content"
                    htmlFor="content"
                    error={fieldState.error}
                    className="sm:col-span-2"
                  >
                    <Textarea id="content" rows={5} {...field} />
                  </FormField>
                )}
              />
            </div>
          </FormPanel>
        </div>

        <aside className="lg:sticky lg:top-4 lg:self-start">
          <BannerPreview
            values={watchValues}
            imageUrl={desktopPreview}
            categoryOptions={categoryOptions}
          />
        </aside>
      </div>

      <FormSaveBar
        cancelHref={LIST_HREF}
        isSaving={isSaving}
        saveLabel="Save changes"
        onReset={() => {
          form.reset(initial ? rowToFormValues(initial) : bannerFormDefaults);
          setDesktopFile(null);
          setMobileFile(null);
          setDesktopPreview(initial?.imageUrl ?? null);
        }}
      />
    </form>
  );
}
