"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import {
  useForm,
  useFieldArray,
  type Control,
  type Resolver,
  type UseFormRegister,
  type UseFormReturn,
} from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
import { Info, Plus, Trash2 } from "lucide-react";
import { PageHeader, Breadcrumbs } from "@/components/shared/page-header";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/input";
import { FormField } from "@/components/ui/form-field";
import { Alert } from "@/components/ui/alert";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { useT } from "@/i18n";
import { createOrder } from "@/services/orders";
import { friendlyErrorMessage, applyFieldErrors } from "@/lib/errors";
import { APP_CURRENCY } from "@/config/site";
import { cn } from "@/lib/cn";

/** Empty string and number union — the classic "optional numeric input" shape. */
const optionalNumber = z.union([z.literal(""), z.coerce.number()]).optional();

const itemSchema = z.object({
  name: z.string().min(1, "errors.required"),
  quantity: z.coerce.number().int().min(1, "errors.required"),
  unit_price: optionalNumber,
  note: z.string().optional(),

  /** The shop's product code, when whoever is typing has one to hand. */
  sku: z.string().max(255).optional(),

  /**
   * A picture of the line, as a link the shop already hosts.
   *
   * `https` only, because the API refuses anything else — a captain's phone would block a mixed
   * -content image anyway, so accepting `http` here would only move the failure further away
   * from the person who could fix it.
   */
  image_url: z.union([z.literal(""), z.string().url("errors.url").max(2048)]).optional(),

  /**
   * What tells this line apart from the next one with the same name.
   *
   * Typed as free pairs rather than a colour box and a size box, because the attributes are the
   * shop's: one sells shirts and sends `size`, another sells cake and sends `flavour`. Capped at
   * ten to match what the API accepts.
   */
  variant: z
    .array(z.object({ key: z.string().optional(), value: z.string().optional() }))
    .max(10)
    .optional(),
});

/**
 * One counter the goods are collected from.
 *
 * The address is the only part a captain truly needs; the name is what tells three stops apart
 * on a phone screen, and the pin is what makes the stop routable. Coordinates stay optional and
 * paired, exactly as this form has always treated the single pickup.
 */
const supplierSchema = z.object({
  name: z.string().optional(),
  address: z.string().min(1, "errors.required"),
  lat: optionalNumber.default(""),
  lng: optionalNumber.default(""),

  /*
   * What is collected here.
   *
   * Held under the shop rather than in a list of its own, because that is what the line
   * actually is: a thing picked up at a counter. A flat list with a "which shop" box beside
   * every row asks the same question once per line and lets the two disagree — four lines
   * under a shop nobody is visiting is a state this shape cannot reach.
   */
  items: z.array(itemSchema).optional(),
});

/** How many counters one order may be gathered from. The server allows the same three. */
const MAX_SUPPLIERS = 3;

const formSchema = z.object({
  customer_name: z.string().min(1, "errors.required"),
  customer_phone: z.string().optional(),
  /*
   * The shops this order is collected from, in the order the captain should visit them.
   *
   * A list rather than one address, because the goods for a single delivery routinely sit in
   * two or three places — and a second supplier written into the note field is a stop that the
   * route plan, the per-counter confirmation and the per-counter shortfall cannot see.
   *
   * The first entry is sent as the order's own pickup; the rest go as `additional_pickups`.
   */
  suppliers: z.array(supplierSchema).min(1).max(MAX_SUPPLIERS),

  dropoff_address: z.string().min(1, "errors.required"),
  dropoff_lat: optionalNumber.default(""),
  dropoff_lng: optionalNumber.default(""),
  note: z.string().optional(),
  customer_note: z.string().optional(),

  // Required by the API, and it has no safe default. `withPaymentTerms()` falls back to
  // cash on delivery when the field is absent, so an order that was actually prepaid would
  // tell the captain to collect money the customer has already paid.
  payment_method: z.enum(["cash_on_delivery", "prepaid"]),
  amount_to_collect: optionalNumber.default(""),

  /*
   * What kind of order this is. A wrapped one becomes two linked rows on the server — a
   * collection leg from the supplier to the wrapping shop, then the delivery the customer
   * waits for — so the choice has to be made here, before anything is written.
   *
   * A store carries its wrapping shop on its own record and asks for wrapping with a flag.
   * An order typed in here belongs to no store, so the shop comes with the request.
   */
  needs_wrapping: z.boolean().default(false),
  wrapping_name: z.string().optional(),
  wrapping_address: z.string().optional(),
  wrapping_lat: optionalNumber.default(""),
  wrapping_lng: optionalNumber.default(""),
})
  // Enforced here as well as by the server, so somebody choosing cash is told before they
  // submit rather than by a 422 after it.
  .refine(
    (values) =>
      values.payment_method !== "cash_on_delivery" ||
      (values.amount_to_collect !== "" && values.amount_to_collect !== undefined),
    { path: ["amount_to_collect"], message: "errors.required" },
  )
  /*
   * The shop and its pin together or not at all, matching the server rule. A collection leg
   * whose drop-off is an address with no coordinates cannot be routed to, and an order that
   * cannot be delivered is worse than one that was never wrapped — so it is refused here,
   * on the field, rather than as a 422 after the person has left the page.
   */
  .superRefine((values, ctx) => {
    if (!values.needs_wrapping) {
      return;
    }

    for (const field of ["wrapping_address", "wrapping_lat", "wrapping_lng"] as const) {
      if (values[field] === "" || values[field] === undefined) {
        ctx.addIssue({ code: z.ZodIssueCode.custom, path: [field], message: "errors.required" });
      }
    }
  });

type FormValues = z.infer<typeof formSchema>;

// `z.coerce.number()` widens schema input types to `unknown`; the resolver is
// handed a `Resolver` whose input matches the form's already-coerced values.
const resolver = zodResolver(formSchema) as unknown as Resolver<FormValues>;

type PayloadSupplier = {
  name: string | null;
  address: string;
  lat: number | null;
  lng: number | null;
};

type PayloadItem = {
  name: string;
  quantity: number;
  pickup_index?: number;
  unit_price: number | null;
  note: string | null;
  sku: string | null;
  image_url: string | null;
  variant: Record<string, string> | null;
};

interface OrderPayload {
  customer_name: string;
  customer_phone: string | null;
  pickup_address: string;
  pickup_name: string | null;
  pickup_lat: number | null;
  pickup_lng: number | null;

  // Only the shops after the first; absent entirely when there is just the one.
  additional_pickups?: PayloadSupplier[];

  dropoff_address: string;
  dropoff_lat: number | null;
  dropoff_lng: number | null;
  note: string | null;
  fee: number | null;
  currency: string | null;
  customer_note: string | null;
  payment_method: "cash_on_delivery" | "prepaid";
  amount_to_collect: number | null;
  items: PayloadItem[];

  // Sent only for a wrapped order; the server treats their absence as an ordinary one.
  needs_wrapping?: boolean;
  wrapping_name?: string | null;
  wrapping_address?: string;
  wrapping_lat?: number;
  wrapping_lng?: number;
}

/** The filled-in attribute pairs as the object the API takes, or null when there are none. */
const toVariant = (pairs: { key?: string; value?: string }[] | undefined): Record<string, string> | null => {
  const filled = (pairs ?? []).filter((pair) => pair.key?.trim() && pair.value?.trim());

  if (filled.length === 0) {
    return null;
  }

  return Object.fromEntries(filled.map((pair) => [pair.key!.trim(), pair.value!.trim()]));
};

/** Where each flattened line came from, so a server error can be sent back to its input. */
type LineOrigin = { supplierIndex: number; itemIndex: number };

/**
 * A server field name, as this form holds it.
 *
 * Three shapes differ between the two. `pickup_address` is the first shop's address and
 * `additional_pickups.0.address` the second shop's, while the form keeps one list; and
 * `items.4.name` is a position in a flat list the form never had, so it is looked up in the
 * origins recorded while flattening. Anything else passes through untouched.
 */
const formField = (field: string, lines: LineOrigin[]): string => {
  const primary = field.match(/^pickup_(address|name|lat|lng)$/);
  if (primary) {
    return `suppliers.0.${primary[1]}`;
  }

  const extra = field.match(/^additional_pickups\.(\d+)\.(address|name|lat|lng)$/);
  if (extra) {
    return `suppliers.${Number(extra[1]) + 1}.${extra[2]}`;
  }

  const line = field.match(/^items\.(\d+)\.(.+)$/);
  if (line) {
    const origin = lines[Number(line[1])];

    // An index we cannot place — the server counting lines differently than we sent them —
    // is left alone rather than guessed at. A message on the wrong line is worse than one
    // that only reaches the banner.
    if (origin) {
      return `suppliers.${origin.supplierIndex}.items.${origin.itemIndex}.${line[2]}`;
    }
  }

  return field;
};

const toNumberOrNull = (value: string | number | undefined) =>
  value === "" || value === undefined || value === null ? null : Number(value);

export default function NewOrderPage() {
  const t = useT();
  const router = useRouter();
  const [serverError, setServerError] = useState<string | null>(null);

  const form = useForm<FormValues>({
    resolver,
    mode: "onTouched",
    defaultValues: {
      customer_name: "",
      customer_phone: "",
      suppliers: [{ name: "", address: "", lat: "", lng: "", items: [] }],
      dropoff_address: "",
      dropoff_lat: "",
      dropoff_lng: "",
      note: "",
      customer_note: "",
      // Cash is the common case here, but it is a *chosen* default on a visible control
      // rather than a silent one — the person creating the order can see what it says.
      payment_method: "cash_on_delivery",
      amount_to_collect: "",
      needs_wrapping: false,
      wrapping_name: "",
      wrapping_address: "",
      wrapping_lat: "",
      wrapping_lng: "",
    },
  });

  // Read rather than destructured so the pickup labels and the shop card re-render with it.
  const needsWrapping = form.watch("needs_wrapping");

  const suppliers = useFieldArray({ control: form.control, name: "suppliers" });

  async function onSubmit(values: FormValues) {
    setServerError(null);

    /*
     * Every line, in the order the API will see them, each remembering the shop it was typed
     * under. The second half matters as much as the first: the server refuses a bad line by
     * its position in the flat list, and without this the message would have nowhere to land.
     */
    const lines = values.suppliers.flatMap((supplier, supplierIndex) =>
      (supplier.items ?? []).map((item, itemIndex) => ({ item, supplierIndex, itemIndex })),
    );

    const payload: OrderPayload = {
      customer_name: values.customer_name,
      customer_phone: values.customer_phone || null,

      // The first shop is the order's own pickup; the rest travel beside it. Sending a bare
      // `additional_pickups: []` would be a list of nothing, so a one-shop order omits it.
      pickup_address: values.suppliers[0].address,
      pickup_name: values.suppliers[0].name?.trim() || null,
      pickup_lat: toNumberOrNull(values.suppliers[0].lat),
      pickup_lng: toNumberOrNull(values.suppliers[0].lng),
      ...(values.suppliers.length > 1
        ? {
            additional_pickups: values.suppliers.slice(1).map((supplier) => ({
              name: supplier.name?.trim() || null,
              address: supplier.address,
              lat: toNumberOrNull(supplier.lat),
              lng: toNumberOrNull(supplier.lng),
            })),
          }
        : {}),

      dropoff_address: values.dropoff_address,
      dropoff_lat: toNumberOrNull(values.dropoff_lat),
      dropoff_lng: toNumberOrNull(values.dropoff_lng),
      note: values.note || null,
      // Priced by the server from the drop-off area and the value band, never from this form.
      fee: null,
      currency: APP_CURRENCY,
      customer_note: values.customer_note || null,
      payment_method: values.payment_method,
      // The API excludes this outright for a prepaid order, so sending a stray number
      // would be ignored at best and confusing in the request log at worst.
      amount_to_collect:
        values.payment_method === "cash_on_delivery"
          ? toNumberOrNull(values.amount_to_collect)
          : null,
      // The API takes one list with each line naming its stop; the form holds a list per shop.
      // Flattened here, in visiting order, so `pickup_index` is simply where the line was typed.
      items: lines.map(({ item, supplierIndex }) => ({
        name: item.name,
        quantity: item.quantity,
        /*
         * Always sent now, including on a one-shop order. Under the old flat list it was a
         * guess nobody had made, so saying `0` would have been our claim; under this shape the
         * line sits beneath a shop because somebody put it there. Saying so is what lets the
         * captain confirm counter by counter and a shortfall point at the shop it happened in.
         */
        pickup_index: supplierIndex,
        unit_price: toNumberOrNull(item.unit_price),
        note: item.note || null,
        sku: item.sku?.trim() || null,
        image_url: item.image_url?.trim() || null,
        // Only the pairs that have both halves. A key somebody started typing and abandoned is
        // not an attribute, and sending `{"": ""}` would put an empty chip on the captain's phone.
        variant: toVariant(item.variant),
      })),
      /*
       * Only sent when it was asked for. The shop is validated as a set above, so by here
       * the three parts are either all present or the submit never happened — the casts
       * are reading values the resolver has already proved.
       */
      ...(values.needs_wrapping
        ? {
            needs_wrapping: true,
            wrapping_name: values.wrapping_name?.trim() || null,
            wrapping_address: values.wrapping_address!,
            wrapping_lat: Number(values.wrapping_lat),
            wrapping_lng: Number(values.wrapping_lng),
          }
        : {}),
    };

    try {
      const response = await createOrder(payload);
      toast.success(response.Message || t("orders.createSuccess"), {
        // A wrapped order leaves the page showing one order while two were written; saying so
        // here is the only moment the person learns the collection leg exists.
        description: values.needs_wrapping ? t("orders.wrappedCreated") : undefined,
      });
      const order = response.Model;
      if (order) {
        router.replace(`/orders/${order.uuid}`);
        return;
      }
      router.replace("/orders");
    } catch (error) {
      setServerError(friendlyErrorMessage(error, t));
      applyFieldErrors(error, (field, message) =>
        // The server names the first shop `pickup_*`, the rest `additional_pickups.N.*`, and
        // every line by its place in one flat list — none of which is how this form holds
        // them. Without the translation a refusal lands on a name no input is registered
        // under, and the page shows a banner over a form with nothing marked.
        form.setError(formField(field, lines) as never, { message }),
      );
    }
  }

  return (
    <div className="mx-auto max-w-4xl">
      <Breadcrumbs
        items={[
          { label: t("nav.orders"), href: "/orders" },
          { label: t("orders.createTitle") },
        ]}
      />
      <form onSubmit={form.handleSubmit(onSubmit)} noValidate>
        <PageHeader
          title={t("orders.createTitle")}
          subtitle={t("orders.createSubtitle")}
          actions={
            <Button type="submit" loading={form.formState.isSubmitting}>
              {t("orders.create")}
            </Button>
          }
        />
        {serverError ? <Alert variant="destructive" className="mb-6" title={serverError} /> : null}

        {/*
          * First, because it changes what the fields below mean: for a wrapped order the
          * pickup address is the supplier the goods are collected *from*, and the customer is
          * driven to from the wrapping shop instead.
          */}
        <Card className="mb-4">
          <CardHeader>
            <CardTitle>{t("orders.kind")}</CardTitle>
          </CardHeader>
          <CardContent className="grid gap-3 sm:grid-cols-2">
            {([
              { wrapped: false, label: "orders.kindNormal", hint: "orders.kindNormalHint" },
              { wrapped: true, label: "orders.kindWrapped", hint: "orders.kindWrappedHint" },
            ] as const).map((choice) => (
              <label
                key={String(choice.wrapped)}
                className={cn(
                  "flex cursor-pointer gap-3 rounded-lg border p-3 transition-colors",
                  needsWrapping === choice.wrapped
                    ? "border-primary bg-primary/5"
                    : "hover:border-primary/30",
                )}
              >
                {/* A real radio, so the pair is one tab stop and arrow keys move between them. */}
                <input
                  type="radio"
                  name="order_kind"
                  className="mt-1 h-4 w-4 shrink-0 accent-[var(--primary)]"
                  checked={needsWrapping === choice.wrapped}
                  onChange={() =>
                    form.setValue("needs_wrapping", choice.wrapped, { shouldValidate: true })
                  }
                />
                <span>
                  <span className="block text-sm font-medium">{t(choice.label)}</span>
                  <span className="mt-1 block text-xs text-muted-foreground">{t(choice.hint)}</span>
                </span>
              </label>
            ))}
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle>{t("orders.customer")}</CardTitle>
          </CardHeader>
          <CardContent className="grid gap-4 sm:grid-cols-2">
            <FormField
              label={t("orders.customerName")}
              htmlFor="customer_name"
              required
              error={form.formState.errors.customer_name?.message}
            >
              <Input id="customer_name" {...form.register("customer_name")} />
            </FormField>
            <FormField
              label={t("orders.customerPhone")}
              htmlFor="customer_phone"
              error={form.formState.errors.customer_phone?.message}
            >
              <Input id="customer_phone" dir="ltr" placeholder="+966 5x xxx xxxx" {...form.register("customer_phone")} />
            </FormField>
          </CardContent>
        </Card>

        <Card className="mt-4">
          <CardHeader>
            <CardTitle>{t("orders.suppliers")}</CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            {needsWrapping ? (
              <p className="flex items-start gap-2 text-sm text-muted-foreground">
                <Info className="mt-0.5 h-4 w-4 shrink-0" aria-hidden />
                {t("orders.pickupHintWrapped")}
              </p>
            ) : null}

            {suppliers.fields.map((field, index) => (
              <div key={field.id} className="rounded-lg border p-3">
                <div className="mb-3 flex items-center justify-between gap-2">
                  <p className="text-sm font-medium">
                    {t("orders.supplierNumber", { number: index + 1 })}
                  </p>
                  {/* The first shop is the order's own pickup and cannot be dropped — removing
                      it would leave an order collected from nowhere. */}
                  {index > 0 ? (
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      onClick={() => suppliers.remove(index)}
                      aria-label={t("orders.removeSupplier")}
                    >
                      <Trash2 className="h-4 w-4" aria-hidden />
                    </Button>
                  ) : null}
                </div>

                <div className="grid gap-4">
                  <div className="grid gap-4 sm:grid-cols-2">
                    <FormField
                      label={t("orders.supplierName")}
                      htmlFor={`suppliers.${index}.name`}
                      hint={index === 0 ? t("orders.supplierNameHint") : undefined}
                      error={form.formState.errors.suppliers?.[index]?.name?.message}
                    >
                      <Input id={`suppliers.${index}.name`} {...form.register(`suppliers.${index}.name`)} />
                    </FormField>
                    <FormField
                      label={needsWrapping ? t("orders.pickupAddressWrapped") : t("orders.pickupAddress")}
                      htmlFor={`suppliers.${index}.address`}
                      required
                      error={form.formState.errors.suppliers?.[index]?.address?.message}
                    >
                      <Input id={`suppliers.${index}.address`} {...form.register(`suppliers.${index}.address`)} />
                    </FormField>
                  </div>
                  <div className="grid gap-4 sm:grid-cols-2">
                    <FormField
                      label={t("orders.pickupLat")}
                      htmlFor={`suppliers.${index}.lat`}
                      hint={index === 0 ? t("orders.latLngHint") : undefined}
                      error={form.formState.errors.suppliers?.[index]?.lat?.message}
                    >
                      <Input
                        id={`suppliers.${index}.lat`}
                        dir="ltr"
                        inputMode="decimal"
                        placeholder="33.5138"
                        {...form.register(`suppliers.${index}.lat`)}
                      />
                    </FormField>
                    <FormField
                      label={t("orders.pickupLng")}
                      htmlFor={`suppliers.${index}.lng`}
                      error={form.formState.errors.suppliers?.[index]?.lng?.message}
                    >
                      <Input
                        id={`suppliers.${index}.lng`}
                        dir="ltr"
                        inputMode="decimal"
                        placeholder="36.2765"
                        {...form.register(`suppliers.${index}.lng`)}
                      />
                    </FormField>
                  </div>

                  {/* What is picked up here, under the shop it is picked up from. */}
                  <SupplierItems supplier={index} form={form} t={t} />
                </div>
              </div>
            ))}

            {suppliers.fields.length < MAX_SUPPLIERS ? (
              <div>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => suppliers.append({ name: "", address: "", lat: "", lng: "" })}
                >
                  <Plus className="h-4 w-4" aria-hidden />
                  {t("orders.addSupplier")}
                </Button>
                <p className="mt-2 text-xs text-muted-foreground">{t("orders.addSupplierHint")}</p>
              </div>
            ) : (
              <p className="text-xs text-muted-foreground">
                {t("orders.supplierLimit", { max: MAX_SUPPLIERS })}
              </p>
            )}
          </CardContent>
        </Card>

        {needsWrapping ? (
          <Card className="mt-4">
            <CardHeader>
              <CardTitle>{t("orders.wrappingShop")}</CardTitle>
            </CardHeader>
            <CardContent className="grid gap-4">
              <p className="flex items-start gap-2 text-sm text-muted-foreground">
                <Info className="mt-0.5 h-4 w-4 shrink-0" />
                {t("orders.wrappingShopHint")}
              </p>
              <div className="grid gap-4 sm:grid-cols-2">
                <FormField
                  label={t("orders.wrappingName")}
                  htmlFor="wrapping_name"
                  error={form.formState.errors.wrapping_name?.message}
                >
                  <Input id="wrapping_name" {...form.register("wrapping_name")} />
                </FormField>
                <FormField
                  label={t("orders.wrappingAddress")}
                  htmlFor="wrapping_address"
                  required
                  error={form.formState.errors.wrapping_address?.message}
                >
                  <Input id="wrapping_address" {...form.register("wrapping_address")} />
                </FormField>
              </div>
              <div className="grid gap-4 sm:grid-cols-2">
                <FormField
                  label={t("orders.wrappingLat")}
                  htmlFor="wrapping_lat"
                  required
                  error={form.formState.errors.wrapping_lat?.message}
                >
                  <Input id="wrapping_lat" dir="ltr" inputMode="decimal" placeholder="33.5192" {...form.register("wrapping_lat")} />
                </FormField>
                <FormField
                  label={t("orders.wrappingLng")}
                  htmlFor="wrapping_lng"
                  required
                  error={form.formState.errors.wrapping_lng?.message}
                >
                  <Input id="wrapping_lng" dir="ltr" inputMode="decimal" placeholder="36.2877" {...form.register("wrapping_lng")} />
                </FormField>
              </div>
            </CardContent>
          </Card>
        ) : null}

        <Card className="mt-4">
          <CardHeader>
            <CardTitle>{t("orders.dropoff")}</CardTitle>
          </CardHeader>
          <CardContent className="grid gap-4">
            <FormField
              label={t("orders.dropoffAddress")}
              htmlFor="dropoff_address"
              required
              error={form.formState.errors.dropoff_address?.message}
            >
              <Input id="dropoff_address" {...form.register("dropoff_address")} />
            </FormField>
            <div className="grid gap-4 sm:grid-cols-2">
              <FormField label={t("orders.dropoffLat")} htmlFor="dropoff_lat" error={form.formState.errors.dropoff_lat?.message}>
                <Input id="dropoff_lat" dir="ltr" inputMode="decimal" placeholder="24.7136" {...form.register("dropoff_lat")} />
              </FormField>
              <FormField label={t("orders.dropoffLng")} htmlFor="dropoff_lng" error={form.formState.errors.dropoff_lng?.message}>
                <Input id="dropoff_lng" dir="ltr" inputMode="decimal" placeholder="46.6753" {...form.register("dropoff_lng")} />
              </FormField>
            </div>
          </CardContent>
        </Card>

        <Card className="mt-4">
          <CardHeader>
            <CardTitle>{t("orders.note")}</CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            <FormField label={t("orders.note")} htmlFor="note" error={form.formState.errors.note?.message}>
              <Textarea id="note" rows={3} {...form.register("note")} />
            </FormField>

            {/*
              The fee is not typed here, and the currency is not a choice.
              
              Delivery is priced from the area the drop-off falls in and the value band the goods
              reach, both of which the server works out when the order is written. A box here
              could only disagree with that: the ladder overrules a stated fee anyway, so anything
              typed in would be recorded as what somebody asked for and then replaced — which
              reads, on the order afterwards, exactly like the form having lost the input.
            */}
            <p className="flex items-start gap-2 rounded-lg border bg-muted/30 p-3 text-sm text-muted-foreground">
              <Info className="mt-0.5 h-4 w-4 shrink-0" aria-hidden />
              {t("orders.feeAutomatic")}
            </p>
          </CardContent>
        </Card>

        <Card className="mt-6">
          <CardHeader>
            <CardTitle>{t("orders.payment")}</CardTitle>
          </CardHeader>
          <CardContent className="grid gap-4 sm:grid-cols-2">
            <FormField
              label={t("orders.paymentMethod")}
              htmlFor="payment_method"
              error={form.formState.errors.payment_method?.message}
            >
              <Select
                value={form.watch("payment_method")}
                onValueChange={(value) =>
                  form.setValue("payment_method", value as "cash_on_delivery" | "prepaid", {
                    shouldValidate: true,
                  })
                }
              >
                <SelectTrigger id="payment_method">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="cash_on_delivery">
                    {t("orders.paymentMethod.cash_on_delivery")}
                  </SelectItem>
                  <SelectItem value="prepaid">{t("orders.paymentMethod.prepaid")}</SelectItem>
                </SelectContent>
              </Select>
            </FormField>

            {/*
              Only for cash. A prepaid order has nothing to collect, and the API excludes the
              field entirely — showing an input there would invite somebody to fill it in and
              wonder why it vanished.
            */}
            {form.watch("payment_method") === "cash_on_delivery" ? (
              <FormField
                label={t("orders.amountToCollect")}
                htmlFor="amount_to_collect"
                error={form.formState.errors.amount_to_collect?.message}
              >
                <Input
                  id="amount_to_collect"
                  type="number"
                  min={0}
                  step="0.01"
                  dir="ltr"
                  {...form.register("amount_to_collect", { valueAsNumber: true })}
                />
              </FormField>
            ) : null}

            <div className="sm:col-span-2">
              <FormField
                label={t("orders.customerNote")}
                htmlFor="customer_note"
                error={form.formState.errors.customer_note?.message}
              >
                <Textarea id="customer_note" rows={2} {...form.register("customer_note")} />
              </FormField>
            </div>
          </CardContent>
        </Card>

        <div className="mt-6 flex justify-end gap-2">
          <Button type="button" variant="outline" onClick={() => router.back()}>
            {t("common.cancel")}
          </Button>
          <Button type="submit" loading={form.formState.isSubmitting}>
            {t("orders.create")}
          </Button>
        </div>
      </form>
    </div>
  );
}
/**
 * What is collected from one shop.
 *
 * A list of its own per supplier, rather than one list for the order with a "which shop" box
 * on every row. The two carry the same facts, but only this one makes them impossible to
 * contradict: a line is under the shop it comes from because that is where it was typed, and
 * removing a shop takes its lines with it instead of leaving them pointing at a stop that is
 * no longer there.
 *
 * It also reads the way the errand runs. A captain stands at a counter and collects *these*;
 * the screen that describes the errand should be grouped the same way.
 */
function SupplierItems({
  supplier,
  form,
  t,
}: {
  supplier: number;
  form: UseFormReturn<FormValues>;
  t: ReturnType<typeof useT>;
}) {
  const { fields, append, remove } = useFieldArray({
    control: form.control,
    name: `suppliers.${supplier}.items`,
  });

  const errors = form.formState.errors.suppliers?.[supplier]?.items;

  return (
    <div className="border-t pt-3">
      <p className="mb-2 text-sm font-medium">{t("orders.itemsFromThisShop")}</p>

      {fields.length === 0 ? (
        <p className="mb-2 text-sm text-muted-foreground">{t("orders.noItemsHere")}</p>
      ) : null}

      <div className="space-y-3">
        {fields.map((field, index) => (
          <div key={field.id} className="rounded-lg border bg-muted/20 p-3">
            <div className="grid gap-3 sm:grid-cols-[1fr_6rem_6rem_2rem]">
              <FormField
                label={t("orders.item")}
                htmlFor={`suppliers.${supplier}.items.${index}.name`}
                error={errors?.[index]?.name?.message}
              >
                <Input
                  id={`suppliers.${supplier}.items.${index}.name`}
                  placeholder={t("orders.itemPlaceholder")}
                  {...form.register(`suppliers.${supplier}.items.${index}.name`)}
                />
              </FormField>
              <FormField
                label={t("orders.quantity")}
                htmlFor={`suppliers.${supplier}.items.${index}.quantity`}
                error={errors?.[index]?.quantity?.message}
              >
                <Input
                  id={`suppliers.${supplier}.items.${index}.quantity`}
                  type="number"
                  min={1}
                  dir="ltr"
                  {...form.register(`suppliers.${supplier}.items.${index}.quantity`, { valueAsNumber: true })}
                />
              </FormField>
              <FormField
                label={t("orders.unitPrice")}
                htmlFor={`suppliers.${supplier}.items.${index}.unit_price`}
                error={errors?.[index]?.unit_price?.message}
              >
                <Input
                  id={`suppliers.${supplier}.items.${index}.unit_price`}
                  type="number"
                  min={0}
                  dir="ltr"
                  {...form.register(`suppliers.${supplier}.items.${index}.unit_price`, { valueAsNumber: true })}
                />
              </FormField>
              <span className="flex items-end justify-end">
                <Button
                  type="button"
                  variant="ghost"
                  size="icon"
                  className="text-muted-foreground hover:text-destructive"
                  onClick={() => remove(index)}
                  aria-label={t("orders.removeItem")}
                >
                  <Trash2 className="h-4 w-4" />
                </Button>
              </span>
            </div>

            {/*
              The code and what tells this line apart from the next one with the same name.
              Tucked under the row rather than beside it: most back-office orders are typed
              without either, and widening every row for the uncommon case costs the common one.
            */}
            <div className="mt-3 grid gap-3 border-t pt-3 sm:grid-cols-[12rem_1fr]">
              <div className="space-y-3">
                <FormField label={t("orders.itemSku")} htmlFor={`suppliers.${supplier}.items.${index}.sku`}>
                  <Input
                    id={`suppliers.${supplier}.items.${index}.sku`}
                    dir="ltr"
                    placeholder="SHIRT-RED-L"
                    {...form.register(`suppliers.${supplier}.items.${index}.sku`)}
                  />
                </FormField>
                <FormField
                  label={t("orders.itemImage")}
                  htmlFor={`suppliers.${supplier}.items.${index}.image_url`}
                  error={errors?.[index]?.image_url?.message}
                >
                  <Input
                    id={`suppliers.${supplier}.items.${index}.image_url`}
                    dir="ltr"
                    type="url"
                    placeholder="https://…"
                    {...form.register(`suppliers.${supplier}.items.${index}.image_url`)}
                  />
                </FormField>
              </div>
              <ItemVariantFields
                control={form.control}
                register={form.register}
                supplier={supplier}
                index={index}
                t={t}
              />
            </div>
          </div>
        ))}
      </div>

      <Button
        type="button"
        variant="outline"
        size="sm"
        className="mt-3"
        onClick={() => append({ name: "", quantity: 1, unit_price: "", note: "" })}
      >
        <Plus className="h-4 w-4" aria-hidden />
        {t("orders.addItem")}
      </Button>
    </div>
  );
}

/**
 * The attribute pairs on one line: colour, size, flavour — whatever this shop sells by.
 *
 * Free pairs rather than fixed boxes, because the attributes belong to the shop and not to us.
 * Giving the form a Colour field and a Size field would quietly tell everybody that those are
 * the two that exist, and the first order of cake would have its flavour typed into Colour.
 *
 * Starts empty. A row of blank inputs on every line reads as something waiting to be filled in,
 * and most orders have nothing to put there.
 */
function ItemVariantFields({
  control,
  register,
  supplier,
  index,
  t,
}: {
  control: Control<FormValues>;
  register: UseFormRegister<FormValues>;
  supplier: number;
  index: number;
  t: ReturnType<typeof useT>;
}) {
  const { fields, append, remove } = useFieldArray({
    control,
    name: `suppliers.${supplier}.items.${index}.variant`,
  });

  return (
    <div>
      <p className="mb-1.5 text-sm font-medium text-foreground">{t("orders.itemVariant")}</p>

      <div className="space-y-2">
        {fields.map((field, pair) => (
          <div key={field.id} className="flex items-center gap-2">
            <Input
              aria-label={t("orders.itemVariantKey")}
              placeholder={t("orders.itemVariantKeyPlaceholder")}
              className="w-40"
              {...register(`suppliers.${supplier}.items.${index}.variant.${pair}.key`)}
            />
            <Input
              aria-label={t("orders.itemVariantValue")}
              placeholder={t("orders.itemVariantValuePlaceholder")}
              {...register(`suppliers.${supplier}.items.${index}.variant.${pair}.value`)}
            />
            <Button
              type="button"
              variant="ghost"
              size="icon"
              className="shrink-0 text-muted-foreground hover:text-destructive"
              onClick={() => remove(pair)}
              aria-label={t("orders.itemVariantRemove")}
            >
              <Trash2 className="h-4 w-4" />
            </Button>
          </div>
        ))}
      </div>

      {fields.length < 10 ? (
        <Button
          type="button"
          variant="outline"
          size="sm"
          className="mt-2"
          onClick={() => append({ key: "", value: "" })}
        >
          <Plus className="me-1 h-4 w-4" />
          {t("orders.itemVariantAdd")}
        </Button>
      ) : null}
    </div>
  );
}
