"use client";

import { useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatCurrency } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { useFieldErrors } from "@/lib/use-field-errors";
import { adjustStoreLedger, settleStoreLedger } from "@/services/store-ledger";
import type { StoreAccountBalance } from "@/types/store-ledger";

/**
 * Recording a payment, or correcting an account.
 *
 * **The direction is never a choice.** A balance can only be cleared one way — a shop we owe gets
 * paid, a shop that owes us pays — so the form reads it off `settle_with` and the server refuses
 * the other. Asking somebody to pick a direction is asking them to record a payment backwards.
 *
 * The amount is entered positive for the same reason. A minus sign typed into a box is the one
 * part of a money form nobody proof-reads.
 *
 * A correction is the exception and is deliberately shaped differently: it is signed, because it
 * undoes something that went the wrong way, and its note is required because no order caused it —
 * nothing else on the row can ever say why it is there.
 */
export function StoreSettleDialog({
  storeUuid,
  storeName,
  balance,
  mode,
  onClose,
}: {
  storeUuid: string;
  storeName: string;
  balance: StoreAccountBalance;
  mode: "settle" | "adjust";
  onClose: () => void;
}) {
  const t = useT();
  const { locale } = useI18n();
  const queryClient = useQueryClient();

  const [amount, setAmount] = useState(
    mode === "settle" && balance.state !== "clear"
      ? String(balance.owed_by_store > 0 ? balance.owed_by_store : balance.owed_to_store)
      : "",
  );
  const [reference, setReference] = useState("");
  const [note, setNote] = useState("");

  const fields = useFieldErrors({ only: ["type", "amount", "currency", "note", "reference"] });

  const num = (value: string) => (value.trim() === "" ? Number.NaN : Number(value));
  const settling = mode === "settle";

  const invalid = settling
    ? Number.isNaN(num(amount)) || num(amount) <= 0 || balance.settle_with === null
    : Number.isNaN(num(amount)) || num(amount) === 0 || note.trim() === "";

  const save = useMutation({
    mutationFn: () =>
      settling
        ? settleStoreLedger(storeUuid, {
            // Read from the balance, never from the form: the only movement that clears an
            // account in this state is the one the server would accept.
            type: balance.settle_with!.direction,
            amount: num(amount),
            currency: balance.currency,
            reference: reference.trim() || undefined,
            note: note.trim() || undefined,
          })
        : adjustStoreLedger(storeUuid, {
            amount: num(amount),
            currency: balance.currency,
            note: note.trim(),
            reference: reference.trim() || undefined,
          }),
    onMutate: fields.reset,
    onSuccess: (response) => {
      toast.success(
        response.Message ?? t(settling ? "storeAccounts.recorded" : "storeAccounts.adjusted"),
      );
      onClose();
      void queryClient.invalidateQueries({ queryKey: queryKeys.storeLedger.all });
    },
    onError: (err) => {
      if (!fields.capture(err)) toast.error(friendlyErrorMessage(err, t));
    },
  });

  return (
    <Dialog
      open
      onOpenChange={(open) => {
        if (!open) onClose();
      }}
    >
      <DialogContent>
        <DialogHeader>
          <DialogTitle>
            {t(settling ? "storeAccounts.settleTitle" : "storeAccounts.adjustTitle")}
          </DialogTitle>
          <DialogDescription>
            {t(settling ? "storeAccounts.settleBody" : "storeAccounts.adjustBody")}
          </DialogDescription>
        </DialogHeader>

        <div className="rounded-lg border bg-muted/40 p-4 text-xs">
          <p className="font-medium text-foreground">{storeName}</p>
          <p className="mt-1 text-muted-foreground">
            {balance.state_label}
            {balance.state !== "clear" ? (
              <span className="numeric ms-1 font-medium text-foreground">
                {formatCurrency(
                  balance.owed_by_store > 0 ? balance.owed_by_store : balance.owed_to_store,
                  balance.currency,
                  locale,
                )}
              </span>
            ) : null}
          </p>
          {settling && balance.settle_with !== null ? (
            <p className="mt-1 text-muted-foreground">{balance.settle_with.label}</p>
          ) : null}
        </div>

        {settling && balance.settle_with === null ? (
          <p className="text-sm text-muted-foreground">{t("storeAccounts.nothingToSettle")}</p>
        ) : (
          <form
            className="space-y-5"
            onSubmit={(event) => {
              event.preventDefault();
              if (invalid || save.isPending) return;
              save.mutate();
            }}
          >
            <div className="space-y-2">
              <Label htmlFor="store-settle-amount">
                {t(settling ? "storeAccounts.settleAmount" : "storeAccounts.adjustAmount")} (
                {balance.currency})
              </Label>
              <Input
                id="store-settle-amount"
                type="number"
                step="0.01"
                dir="ltr"
                value={amount}
                onChange={(event) => setAmount(event.target.value)}
                aria-invalid={fields.get("amount") !== undefined}
                autoFocus
              />
              {fields.get("amount") ? (
                <p className="text-xs text-destructive">{fields.get("amount")}</p>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="store-settle-note">
                {t(settling ? "storeAccounts.settleNote" : "storeAccounts.adjustNote")}
              </Label>
              <Input
                id="store-settle-note"
                value={note}
                onChange={(event) => setNote(event.target.value)}
                aria-invalid={fields.get("note") !== undefined}
              />
              {fields.get("note") ? (
                <p className="text-xs text-destructive">{fields.get("note")}</p>
              ) : !settling ? (
                <p className="text-xs text-muted-foreground">{t("storeAccounts.adjustNoteHint")}</p>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="store-settle-reference">{t("storeAccounts.settleReference")}</Label>
              <Input
                id="store-settle-reference"
                dir="ltr"
                value={reference}
                onChange={(event) => setReference(event.target.value)}
                aria-invalid={fields.get("reference") !== undefined}
              />
              {fields.get("reference") ? (
                <p className="text-xs text-destructive">{fields.get("reference")}</p>
              ) : (
                <p className="text-xs text-muted-foreground">
                  {t("storeAccounts.settleReferenceHint")}
                </p>
              )}
            </div>

            <DialogFooter>
              <Button type="button" variant="outline" onClick={onClose}>
                {t("common.cancel")}
              </Button>
              <Button type="submit" loading={save.isPending} disabled={invalid || save.isPending}>
                {save.isPending ? t("common.saving") : t("common.save")}
              </Button>
            </DialogFooter>
          </form>
        )}
      </DialogContent>
    </Dialog>
  );
}
