"use client";

import { useEffect, useRef, useState } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { ArrowLeft, ChevronDown, Search, Upload } from "lucide-react";
import Link from "next/link";
import ReactSelect, { type DropdownIndicatorProps, type InputProps, type MenuListProps, components } from "react-select";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { Container } from "@/components/common/Container";
import { Card, CardContent } from "@/components/common/Card";
import { Button } from "@/components/common/Button";
import { FormField } from "@/components/app/FormField";
import { useBeneficiaries, useCountryMeta } from "@/hooks/queries/useBeneficiaries";
import { beneficiaryApi } from "@/api/beneficiary.api";
import { isApiError } from "@/lib/apiError";
import { notify } from "@/lib/notify";
import { toFormData } from "@/lib/formData";
import { env } from "@/lib/env";
import { qk } from "@/lib/queryKeys";
import { useTranslation } from "@/hooks/useTranslation";
import { COUNTRIES } from "@/data/countries";
import { cn } from "@/lib/utils";
import { useControlledSelectMenu } from "@/hooks/useControlledSelectMenu";

// Matches the values SendNewBeneficiaryView.tsx / the store endpoint use — the
// update endpoint shares the same "method" contract, so these must stay in sync.
const TRANSACTION_TYPES = ["Bank Transfer", "Mobile Money", "Cash Pickup"];

function normalizeMethod(raw: string): string {
  const m = raw.toLowerCase();
  if (m.includes("bank")) return "Bank Transfer";
  if (m.includes("mobile")) return "Mobile Money";
  return "Cash Pickup";
}
const DOCUMENT_TYPES = ["NID", "Passport", "Driving Licence"];

const TX_OPTIONS = TRANSACTION_TYPES.map((v) => ({ value: v, label: v }));
const COUNTRY_OPTIONS = COUNTRIES.map((c) => ({ value: c.name, label: c.name }));
const DOC_OPTIONS = DOCUMENT_TYPES.map((v) => ({ value: v, label: v }));

// Matches the select labels on this page — 14px, medium weight.
const FIELD_LABEL_CLASSNAME =
  "block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400";

const SELECT_CLASSNAMES = {
  control: () =>
    "h-11 cursor-pointer rounded-2xl border border-slate-200 bg-white px-3 text-sm dark:border-white/[0.08] dark:bg-white/[0.04]",
  menu: () =>
    "z-50 mt-1 min-w-full overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg dark:border-slate-700 dark:bg-slate-900",
  option: ({ isFocused, isSelected }: { isFocused: boolean; isSelected: boolean }) =>
    cn(
      "cursor-pointer px-4 py-2 text-sm",
      isSelected
        ? "bg-brand-600 text-white"
        : isFocused
          ? "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-white"
          : "text-slate-700 dark:text-slate-200",
    ),
  singleValue: () => "text-slate-900 dark:text-white",
  indicatorsContainer: () => "text-slate-400 dark:text-slate-500",
  input: () => "text-slate-900 dark:text-white",
  menuList: () => "max-h-60 overflow-y-auto",
};

// Menu attaches flush to the control (no gap, square-off shared corners) so
// opening reads as the control expanding downward rather than a floating menu.
// Shared by every select on this page.
const FLUSH_SELECT_CLASSNAMES = {
  ...SELECT_CLASSNAMES,
  control: ({ menuIsOpen }: { menuIsOpen: boolean }) =>
    cn(
      "h-11 cursor-pointer border border-slate-200 bg-white px-3 text-sm transition-[border-radius] duration-150 dark:border-white/[0.08] dark:bg-white/[0.04]",
      menuIsOpen ? "rounded-t-2xl rounded-b-none" : "rounded-2xl",
    ),
  menu: () =>
    "overflow-hidden rounded-b-2xl border border-t-0 border-slate-200 bg-white shadow-lg dark:border-slate-700 dark:bg-slate-900",
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function SearchMenuList(props: MenuListProps<any>) {
  return (
    <components.MenuList {...props}>
      <div className="flex items-center gap-2.5 border-b border-slate-200 px-4 dark:border-slate-700">
        <Search className="h-4 w-4 shrink-0 text-slate-400" />
        <input
          autoFocus
          value={props.selectProps.inputValue}
          onChange={(e) =>
            props.selectProps.onInputChange(e.target.value, { action: "input-change", prevInputValue: props.selectProps.inputValue })
          }
          onMouseDown={(e) => e.stopPropagation()}
          onTouchEnd={(e) => e.stopPropagation()}
          placeholder="Search..."
          style={{ outline: "none", boxShadow: "none" }}
          className="flex-1 bg-transparent py-3 text-sm text-slate-900 placeholder:text-slate-400 dark:text-white"
        />
      </div>
      {props.children}
    </components.MenuList>
  );
}

// isSearchable={false} renders DummyInput (ignores components.Input), so we use
// isSearchable={true} + this override: always hidden in control, onBlur stripped
// so autoFocus on the menu's search input doesn't trigger the blur→close chain.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function SearchInput(props: InputProps<any>) {
  const { onBlur: _discarded, ...rest } = props;
  return <components.Input {...rest} isHidden={true} />;
}

const SEARCHABLE_SELECT_COMPONENTS = { DropdownIndicator: TxDropdownIndicator, MenuList: SearchMenuList, Input: SearchInput };

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function TxDropdownIndicator(props: DropdownIndicatorProps<any>) {
  return (
    <components.DropdownIndicator {...props}>
      <ChevronDown
        className={cn(
          "h-4 w-4 text-slate-400 transition-transform duration-200",
          props.selectProps.menuIsOpen && "rotate-180",
        )}
      />
    </components.DropdownIndicator>
  );
}

export function RecipientEditView() {
  const { t } = useTranslation();
  const router = useRouter();
  const id = useSearchParams().get("id") ?? "";
  const queryClient = useQueryClient();
  const { data, isLoading } = useBeneficiaries();
  const pathLocation = data?.image_paths?.path_location;

  function buildImageUrl(filename: string): string {
    if (!filename) return "";
    if (filename.startsWith("http")) return filename;
    return pathLocation && env.STORAGE_URL
      ? `${env.STORAGE_URL}/${pathLocation}/${filename}`
      : filename;
  }

  const beneficiary = data?.beneficiaries.find((b) => String(b.id) === id);

  const [firstName, setFirstName] = useState("");
  const [middleName, setMiddleName] = useState("");
  const [lastName, setLastName] = useState("");
  const [email, setEmail] = useState("");
  const [country, setCountry] = useState("");
  const [countrySearch, setCountrySearch] = useState("");
  const [txSearch, setTxSearch] = useState("");
  const [bankSearch, setBankSearch] = useState("");
  const [mobileSearch, setMobileSearch] = useState("");
  const [cashSearch, setCashSearch] = useState("");
  const [docSearch, setDocSearch] = useState("");
  const countryRef = useRef<HTMLDivElement>(null);
  const countryMenu = useControlledSelectMenu(countryRef, "select-menu-portal");
  const txRef = useRef<HTMLDivElement>(null);
  const txMenu = useControlledSelectMenu(txRef, "select-menu-portal");
  const bankRef = useRef<HTMLDivElement>(null);
  const bankMenu = useControlledSelectMenu(bankRef, "select-menu-portal");
  const mobileRef = useRef<HTMLDivElement>(null);
  const mobileMenu = useControlledSelectMenu(mobileRef, "select-menu-portal");
  const cashRef = useRef<HTMLDivElement>(null);
  const cashMenu = useControlledSelectMenu(cashRef, "select-menu-portal");
  const docRef = useRef<HTMLDivElement>(null);
  const docMenu = useControlledSelectMenu(docRef, "select-menu-portal");
  const [city, setCity] = useState("");
  const [state, setState] = useState("");
  const [zipCode, setZipCode] = useState("");
  const [phone, setPhone] = useState("");
  const [method, setMethod] = useState("Bank Transfer");
  const [bankName, setBankName] = useState("");
  const [ibanNumber, setIbanNumber] = useState("");
  const [accountNumber, setAccountNumber] = useState("");
  const [mobileName, setMobileName] = useState("");
  const [address, setAddress] = useState("");
  const [documentType, setDocumentType] = useState("");
  const [frontImage, setFrontImage] = useState<File | null>(null);
  const [backImage, setBackImage] = useState<File | null>(null);
  const [frontPreview, setFrontPreview] = useState<string | null>(null);
  const [backPreview, setBackPreview] = useState<string | null>(null);

  const frontRef = useRef<HTMLInputElement>(null);
  const backRef = useRef<HTMLInputElement>(null);

  useEffect(() => () => { if (frontPreview) URL.revokeObjectURL(frontPreview); }, [frontPreview]);
  useEffect(() => () => { if (backPreview) URL.revokeObjectURL(backPreview); }, [backPreview]);

  useEffect(() => {
    if (!beneficiary) return;
    setFirstName(beneficiary.first_name);
    setMiddleName(beneficiary.middle_name ?? "");
    setLastName(beneficiary.last_name);
    setEmail(beneficiary.email ?? "");
    setCountry(beneficiary.country);
    setCity(beneficiary.city ?? "");
    setState(beneficiary.state ?? "");
    setZipCode(beneficiary.zip_code ?? "");
    setPhone(beneficiary.phone ?? "");
    const normalizedMethod = normalizeMethod(beneficiary.method || "Bank Transfer");
    setMethod(normalizedMethod);
    setBankName(beneficiary.bank_name ?? "");
    setIbanNumber(beneficiary.iban_number ?? "");
    setAccountNumber(beneficiary.account_number ?? "");
    // Cash Pickup stores its selection under pickup_point, not mobile_name — the form
    // reuses one state field for both (same as SendNewBeneficiaryView.tsx), so read
    // from whichever source field actually matches this recipient's method.
    setMobileName((normalizedMethod === "Cash Pickup" ? beneficiary.pickup_point : beneficiary.mobile_name) ?? "");
    setAddress(beneficiary.address ?? "");
    setDocumentType(beneficiary.document_type ?? "");
  }, [beneficiary]);

  const { data: countryMeta } = useCountryMeta(country);
  type MetaItem = { id: number; name: string };
  // Cash pickup points have a different shape from banks/mobile methods — { id, address }
  // rather than { id, name } — matches SendNewBeneficiaryView.tsx's contract for the
  // same underlying data.
  type CashPickupItem = { id: number; address: string };
  interface CountryMetaData { banks?: MetaItem[]; mobile_methods?: MetaItem[]; cash_pickups?: CashPickupItem[] }
  const meta = countryMeta as CountryMetaData | undefined;
  const bankList: MetaItem[]             = meta?.banks          ?? [];
  const mobileList: MetaItem[]           = meta?.mobile_methods ?? [];
  const cashPickupList: CashPickupItem[] = meta?.cash_pickups   ?? [];

  const bankOptions       = bankList.map((b) => ({ value: b.name, label: b.name }));
  const mobileOptions     = mobileList.map((m) => ({ value: m.name, label: m.name }));
  const cashPickupOptions = cashPickupList.map((c) => ({ value: c.address, label: c.address }));

  const updateMutation = useMutation({
    mutationFn: (fd: FormData) => beneficiaryApi.update(id, fd),
    onSuccess: () => {
      notify(t("app.recipients.edit.success"), "success");
      queryClient.invalidateQueries({ queryKey: qk.beneficiaries.all });
      router.replace("/recipients");
    },
    onError: (err) => {
      notify(isApiError(err) ? err.message : t("app.recipients.edit.saveFailed"), "error");
    },
  });

  function onSubmit(e: { preventDefault(): void }) {
    e.preventDefault();

    const missing: string[] = [];
    if (!firstName.trim()) missing.push("First Name");
    if (!lastName.trim()) missing.push("Last Name");
    if (method === "Bank Transfer") {
      if (!bankName) missing.push("Bank Name");
      if (!ibanNumber.trim()) missing.push("IBAN Number");
    } else if (method === "Mobile Money") {
      if (!mobileName) missing.push("Mobile Method");
      if (!accountNumber.trim()) missing.push("Account Number");
    } else if (method === "Cash Pickup" && !mobileName) {
      missing.push("Pickup Point");
    }
    if (missing.length > 0) {
      notify(t("app.recipients.new.missingFields").replace("{fields}", missing.join(", ")), "error");
      return;
    }

    const base = {
      first_name: firstName,
      middle_name: middleName,
      last_name: lastName,
      email,
      country,
      city,
      state,
      zip_code: zipCode,
      phone,
      method,
      address,
      document_type: documentType,
      front_image: frontImage,
      back_image: backImage,
    };

    const methodFields =
      method === "Bank Transfer"
        ? { bank_name: bankName, iban_number: ibanNumber }
        : method === "Mobile Money"
          ? { mobile_name: mobileName, account_number: accountNumber }
          : method === "Cash Pickup"
            ? { pickup_point: mobileName }
            : {};

    updateMutation.mutate(toFormData({ ...base, ...methodFields }));
  }

  if (isLoading) {
    return (
      <Container className="max-w-full space-y-6">
        <div className="h-5 w-32 animate-pulse rounded-md bg-slate-200 dark:bg-slate-700" />
        <Card>
          <CardContent className="space-y-4">
            {[1, 2, 3, 4].map((i) => (
              <div key={i} className="h-11 animate-pulse rounded-2xl bg-slate-200 dark:bg-slate-700" />
            ))}
          </CardContent>
        </Card>
      </Container>
    );
  }

  if (!beneficiary) {
    return (
      <Container className="max-w-full">
        <Card>
          <CardContent>
            <p className="text-sm text-slate-600 dark:text-slate-300">
              {t("app.recipients.empty")}
            </p>
            <Button
              type="button"
              variant="outline"
              className="mt-4"
              onClick={() => router.push("/recipients")}
            >
              <ArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
              {t("app.recipients.title")}
            </Button>
          </CardContent>
        </Card>
      </Container>
    );
  }

  return (
    <Container className="max-w-full space-y-6">
      <Link
        href="/recipients"
        className="inline-flex items-center gap-1.5 text-sm font-semibold text-slate-600 transition hover:text-brand-600 dark:text-slate-300 dark:hover:text-brand-300"
      >
        <ArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
        {t("app.recipients.title")}
      </Link>

      <header>
        <h1 className="text-2xl font-bold tracking-tight text-slate-900 dark:text-white sm:text-3xl">
          Edit Recipient
        </h1>
      </header>

      <Card>
        <CardContent>
          <form onSubmit={onSubmit} noValidate className="space-y-5">
            {/* Name row */}
            <div className="grid gap-4 sm:grid-cols-3">
              <FormField
                label="First Name"
                placeholder="Enter first name"
                value={firstName}
                onChange={(e) => setFirstName(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
                required
              />
              <FormField
                label="Middle Name"
                placeholder="Enter middle name"
                value={middleName}
                onChange={(e) => setMiddleName(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
              />
              <FormField
                label="Last Name"
                placeholder="Enter last name"
                value={lastName}
                onChange={(e) => setLastName(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
                required
              />
            </div>

            {/* Email */}
            <FormField
              label="Email"
              type="email"
              placeholder="you@example.com"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              labelClassName={FIELD_LABEL_CLASSNAME}
            />

            {/* Country / City / State */}
            <div className="grid gap-4 sm:grid-cols-3">
              <div className="space-y-1.5">
                <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                  Country
                </label>
                <div ref={countryRef}>
                  <ReactSelect
                    unstyled
                    isSearchable
                    inputValue={countrySearch}
                    menuIsOpen={countryMenu.menuIsOpen}
                    onMenuOpen={countryMenu.onMenuOpen}
                    onInputChange={(val, { action }) => { if (action === "input-change") setCountrySearch(val); }}
                    onMenuClose={() => { countryMenu.onMenuClose(); setCountrySearch(""); }}
                    components={SEARCHABLE_SELECT_COMPONENTS}
                    options={COUNTRY_OPTIONS}
                    placeholder="Select Country"
                    value={COUNTRY_OPTIONS.find((o) => o.value === country) ?? null}
                    onChange={(opt) => {
                      setCountry((opt as { value: string } | null)?.value ?? "");
                      setBankName("");
                      setMobileName("");
                    }}
                    classNames={FLUSH_SELECT_CLASSNAMES}
                  />
                </div>
              </div>
              <FormField
                label="City"
                placeholder="Enter city"
                value={city}
                onChange={(e) => setCity(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
              />
              <FormField
                label="State"
                placeholder="Enter state"
                value={state}
                onChange={(e) => setState(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
              />
            </div>

            {/* Zip / Phone */}
            <div className="grid gap-4 sm:grid-cols-2">
              <FormField
                label="Zip Code"
                placeholder="Enter zip code"
                value={zipCode}
                onChange={(e) => setZipCode(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
              />
              <FormField
                label="Phone"
                type="tel"
                placeholder="Enter phone number"
                value={phone}
                onChange={(e) => setPhone(e.target.value)}
                labelClassName={FIELD_LABEL_CLASSNAME}
              />
            </div>

            {/* Transaction Type */}
            <div className="space-y-1.5">
              <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                Transaction Type <span className="text-rose-500">*</span>
              </label>
              <div ref={txRef}>
                <ReactSelect
                  unstyled
                  isSearchable
                  inputValue={txSearch}
                  menuIsOpen={txMenu.menuIsOpen}
                  onMenuOpen={txMenu.onMenuOpen}
                  onInputChange={(val, { action }) => { if (action === "input-change") setTxSearch(val); }}
                  onMenuClose={() => { txMenu.onMenuClose(); setTxSearch(""); }}
                  components={SEARCHABLE_SELECT_COMPONENTS}
                  options={TX_OPTIONS}
                  placeholder="Select Transaction Type"
                  value={TX_OPTIONS.find((o) => o.value === method) ?? null}
                  onChange={(opt) => {
                    setMethod((opt as { value: string } | null)?.value ?? "Bank Transfer");
                    setBankName("");
                    setMobileName("");
                    setAccountNumber("");
                  }}
                  classNames={FLUSH_SELECT_CLASSNAMES}
                />
              </div>
            </div>

            {/* Bank fields */}
            {method === "Bank Transfer" && (
              <div className="grid gap-4 sm:grid-cols-2">
                <div className="space-y-1.5">
                  <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                    Bank Name <span className="text-rose-500">*</span>
                  </label>
                  <div ref={bankRef}>
                    <ReactSelect
                      unstyled
                      isSearchable
                      inputValue={bankSearch}
                      menuIsOpen={bankMenu.menuIsOpen}
                      onMenuOpen={bankMenu.onMenuOpen}
                      onInputChange={(val, { action }) => { if (action === "input-change") setBankSearch(val); }}
                      onMenuClose={() => { bankMenu.onMenuClose(); setBankSearch(""); }}
                      components={SEARCHABLE_SELECT_COMPONENTS}
                      options={bankOptions}
                      placeholder="Select Bank"
                      value={bankOptions.find((o) => o.value === bankName) ?? null}
                      onChange={(opt) => setBankName((opt as { value: string } | null)?.value ?? "")}
                      classNames={FLUSH_SELECT_CLASSNAMES}
                    />
                  </div>
                </div>
                <FormField
                  label="IBAN Number"
                  placeholder="Enter IBAN number"
                  value={ibanNumber}
                  onChange={(e) => setIbanNumber(e.target.value)}
                  labelClassName={FIELD_LABEL_CLASSNAME}
                  required
                />
              </div>
            )}

            {/* Mobile fields */}
            {method === "Mobile Money" && (
              <div className="grid gap-4 sm:grid-cols-2">
                <div className="space-y-1.5">
                  <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                    Mobile Method
                  </label>
                  <div ref={mobileRef}>
                    <ReactSelect
                      unstyled
                      isSearchable
                      inputValue={mobileSearch}
                      menuIsOpen={mobileMenu.menuIsOpen}
                      onMenuOpen={mobileMenu.onMenuOpen}
                      onInputChange={(val, { action }) => { if (action === "input-change") setMobileSearch(val); }}
                      onMenuClose={() => { mobileMenu.onMenuClose(); setMobileSearch(""); }}
                      components={SEARCHABLE_SELECT_COMPONENTS}
                      options={mobileOptions}
                      placeholder="Select Mobile Method"
                      value={mobileOptions.find((o) => o.value === mobileName) ?? null}
                      onChange={(opt) => setMobileName((opt as { value: string } | null)?.value ?? "")}
                      classNames={FLUSH_SELECT_CLASSNAMES}
                    />
                  </div>
                </div>
                <FormField
                  label="Account Number"
                  placeholder="Enter account number"
                  value={accountNumber}
                  onChange={(e) => setAccountNumber(e.target.value)}
                  labelClassName={FIELD_LABEL_CLASSNAME}
                />
              </div>
            )}

            {/* Cash fields */}
            {method === "Cash Pickup" && (
              <div className="space-y-1.5">
                <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                  Pickup Point
                </label>
                <div ref={cashRef}>
                  <ReactSelect
                    unstyled
                    isSearchable
                    inputValue={cashSearch}
                    menuIsOpen={cashMenu.menuIsOpen}
                    onMenuOpen={cashMenu.onMenuOpen}
                    onInputChange={(val, { action }) => { if (action === "input-change") setCashSearch(val); }}
                    onMenuClose={() => { cashMenu.onMenuClose(); setCashSearch(""); }}
                    components={SEARCHABLE_SELECT_COMPONENTS}
                    options={cashPickupOptions}
                    placeholder="Select Pickup Point"
                    value={cashPickupOptions.find((o) => o.value === mobileName) ?? null}
                    onChange={(opt) => setMobileName((opt as { value: string } | null)?.value ?? "")}
                    classNames={FLUSH_SELECT_CLASSNAMES}
                  />
                </div>
              </div>
            )}

            {/* Address */}
            <div className="space-y-1.5">
              <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                Address
              </label>
              <textarea
                value={address}
                onChange={(e) => setAddress(e.target.value)}
                rows={3}
                placeholder="Enter full address"
                className="w-full rounded-2xl border border-slate-200 bg-white px-4 py-3 text-sm outline-none focus:border-brand-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-white"
              />
            </div>

            {/* Document type + uploads */}
            <div className="grid gap-4 sm:grid-cols-3">
              <div className="space-y-1.5">
                <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                  Document Type
                </label>
                <div ref={docRef}>
                  <ReactSelect
                    unstyled
                    isSearchable
                    inputValue={docSearch}
                    menuIsOpen={docMenu.menuIsOpen}
                    onMenuOpen={docMenu.onMenuOpen}
                    onInputChange={(val, { action }) => { if (action === "input-change") setDocSearch(val); }}
                    onMenuClose={() => { docMenu.onMenuClose(); setDocSearch(""); }}
                    components={SEARCHABLE_SELECT_COMPONENTS}
                    options={DOC_OPTIONS}
                    placeholder="Select Document Type"
                    value={DOC_OPTIONS.find((o) => o.value === documentType) ?? null}
                    onChange={(opt) => setDocumentType((opt as { value: string } | null)?.value ?? "")}
                    classNames={FLUSH_SELECT_CLASSNAMES}
                  />
                </div>
              </div>

              {(["front", "back"] as const).map((side) => {
                const _file = side === "front" ? frontImage : backImage;
                const setFile = side === "front" ? setFrontImage : setBackImage;
                const setPreview = side === "front" ? setFrontPreview : setBackPreview;
                const preview = side === "front" ? frontPreview : backPreview;
                const ref = side === "front" ? frontRef : backRef;
                const existingUrl = buildImageUrl(
                  side === "front" ? beneficiary.front_image : beneficiary.back_image,
                );
                const displayUrl = preview ?? existingUrl ?? null;
                return (
                  <div key={side} className="space-y-1.5">
                    <label className="block text-[length:var(--text-sm-fixed)] font-medium capitalize tracking-wider text-slate-500 dark:text-slate-400">
                      {side === "front" ? "Front Part" : "Back Part"}
                    </label>
                    <label
                      className={cn(
                        "relative flex h-28 cursor-pointer overflow-hidden rounded-2xl border-2 border-dashed transition",
                        displayUrl
                          ? "border-brand-400"
                          : "border-slate-200 hover:border-brand-400 dark:border-slate-700",
                      )}
                    >
                      {displayUrl ? (
                        <>
                          <img
                            src={displayUrl}
                            alt={side === "front" ? "Front document" : "Back document"}
                            className="h-full w-full object-contain"
                          />
                          <div className="absolute inset-0 flex items-center justify-center bg-black/40 opacity-0 transition-opacity hover:opacity-100">
                            <span className="rounded bg-black/70 px-2 py-1 text-xs text-white">
                              Click to replace
                            </span>
                          </div>
                        </>
                      ) : (
                        <div className="flex h-full w-full flex-col items-center justify-center gap-2 text-slate-500 dark:text-slate-400">
                          <Upload className="h-5 w-5" />
                          <span className="text-center text-xs">Drop file or click to select</span>
                        </div>
                      )}
                      <input
                        ref={ref}
                        type="file"
                        accept="image/*"
                        className="sr-only"
                        onChange={(e) => {
                          const f = e.target.files?.[0] ?? null;
                          setFile(f);
                          setPreview(f ? URL.createObjectURL(f) : null);
                        }}
                      />
                    </label>
                  </div>
                );
              })}
            </div>

            <Button
              type="submit"
              size="lg"
              loading={updateMutation.isPending}
              className="w-full"
            >
              {updateMutation.isPending ? t("app.recipients.new.saving") : t("app.recipients.new.save")}
            </Button>
          </form>
        </CardContent>
      </Card>
    </Container>
  );
}
