"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { FormField } from "@/components/ui/form-field";
import { Textarea } from "@/components/ui/input";
import { useT } from "@/i18n";
import { applyFieldErrors, friendlyErrorMessage } from "@/lib/errors";
import { queryKeys } from "@/lib/query-keys";
import { cancelOrder } from "@/services/orders";

// The server's own limit; saying it here keeps the refusal on this side of the wire.
const REASON_MAX = 255;

const cancelSchema = z.object({
  reason: z.string().trim().min(1, "errors.required").max(REASON_MAX, "errors.generic"),
});

type CancelValues = z.infer<typeof cancelSchema>;

interface CancelOrderDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  uuid: string;
  orderNumber: string;
  /** Named in the warning: cancelling an order somebody is already carrying is a phone call too. */
  captainName?: string | null;
}

/**
 * Call an order off from the back office.
 *
 * **The reason is required, and it is not a formality.** It is stored on the order and is the only
 * thing that answers "why was this cancelled?" weeks later — for support, for the shop that sent
 * the order, and for the captain who had already driven to the pickup.
 *
 * Captains have no cancel endpoint at all, by design, so this screen is the only way an order is
 * called off once it exists.
 */
export function CancelOrderDialog(props: CancelOrderDialogProps) {
  return (
    <Dialog open={props.open} onOpenChange={props.onOpenChange}>
      <DialogContent>
        {/* Its own component, so every open starts with an empty reason, not last time's. */}
        <CancelForm {...props} />
      </DialogContent>
    </Dialog>
  );
}

function CancelForm({ onOpenChange, uuid, orderNumber, captainName }: CancelOrderDialogProps) {
  const t = useT();
  const queryClient = useQueryClient();
  const form = useForm<CancelValues>({
    resolver: zodResolver(cancelSchema),
    defaultValues: { reason: "" },
  });

  const cancel = useMutation({
    mutationFn: (values: CancelValues) => cancelOrder(uuid, values.reason.trim()),
    onSuccess: (response) => {
      toast.success(response.Message ?? t("orders.cancel.done"));
      onOpenChange(false);
      // This order, every list it sits in, and the live map — the captain's slot just came back.
      void queryClient.invalidateQueries({ queryKey: queryKeys.orders.detail(uuid) });
      void queryClient.invalidateQueries({ queryKey: ["orders"] });
      void queryClient.invalidateQueries({ queryKey: ["tracking"] });
    },
    onError: (error) => {
      // A refused *reason* — too long, or missing — belongs under the box. Whether the order may
      // still be cancelled at all is not a field: it can be delivered while this dialog is open,
      // and that answer stays a toast.
      const shown = applyFieldErrors(
        error,
        (field, message) => form.setError(field as never, { message }),
        { only: ["reason"] },
      );
      if (shown === 0) toast.error(friendlyErrorMessage(error, t));
    },
  });

  return (
    <>
      <DialogHeader>
        <DialogTitle>{t("orders.cancel.title", { order: orderNumber })}</DialogTitle>
        <DialogDescription>
          {captainName
            ? t("orders.cancel.bodyWithCaptain", { name: captainName })
            : t("orders.cancel.body")}
        </DialogDescription>
      </DialogHeader>

      <form
        className="space-y-4"
        onSubmit={form.handleSubmit((values) => {
          if (cancel.isPending) return;
          cancel.mutate(values);
        })}
      >
        <FormField
          label={t("orders.cancel.reason")}
          htmlFor="cancel-reason"
          required
          error={form.formState.errors.reason?.message}
          hint={t("orders.cancel.reasonHint")}
        >
          <Textarea
            id="cancel-reason"
            rows={3}
            maxLength={REASON_MAX}
            placeholder={t("orders.cancel.reasonPlaceholder")}
            {...form.register("reason")}
          />
        </FormField>

        <DialogFooter>
          <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
            {t("common.back")}
          </Button>
          <Button type="submit" variant="destructive" disabled={cancel.isPending}>
            {cancel.isPending ? t("common.saving") : t("orders.cancel.confirm")}
          </Button>
        </DialogFooter>
      </form>
    </>
  );
}
