"use client";

import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Calculator, HandCoins } from "lucide-react";
import { toast } from "sonner";
import { EmptyState, ErrorState, TableSkeleton } from "@/components/shared/states";
import { SettlementStatusBadge } from "@/components/shared/store-badges";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useI18n, useT } from "@/i18n";
import { useCan } from "@/features/auth/use-can";
import { formatCurrency, formatDate } from "@/lib/format";
import { friendlyErrorMessage } from "@/lib/errors";
import { useFieldErrors } from "@/lib/use-field-errors";
import { queryKeys } from "@/lib/query-keys";
import {
  cancelSettlement,
  createSettlement,
  getSettlements,
  previewSettlement,
  settleSettlement,
} from "@/services/settlements";
import { EditSettlementDialog } from "@/features/stores/edit-settlement-dialog";
import type { Settlement, SettlementPreviewRow, StoreClient } from "@/types/store";

/**
 * What we have actually paid a store.
 *
 * The flow is deliberately preview-then-create rather than one form: the point of the preview is
 * that the figures reach a human *before* they become a payment, instead of being retyped off
 * another screen — which is where a transposed digit gets into a bank transfer.
 *
 * The amounts stay editable after the preview fills them, because what is recorded is what
 * somebody agreed to pay. An adjustment, a rounding, a dispute settled halfway: all legitimate,
 * and all different from what the orders imply.
 */
export function StoreSettlements({ store }: { store: StoreClient }) {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const queryClient = useQueryClient();

  const canManage = can("settlements.manage");
  const filters = { page: 1, rows: 25 };

  const { data, isLoading, isError, error, refetch } = useQuery({
    queryKey: queryKeys.storeClients.settlements(store.uuid, filters),
    queryFn: () => getSettlements(store.uuid, filters),
  });

  const [open, setOpen] = useState(false);
  const [from, setFrom] = useState("");
  const [to, setTo] = useState("");
  const [preview, setPreview] = useState<SettlementPreviewRow | null>(null);
  // The draft being corrected, held as the row itself so the dialog opens on the figures that
  // are on screen.
  const [editing, setEditing] = useState<Settlement | null>(null);
  // Shared by the preview and the draft it becomes: the preview is refused on `from`/`to`, the
  // draft on `period_start`/`period_end` and the amounts, and both are typed in this one dialog.
  //
  // The currency and the order count are not claimed: they come from the preview rather than being
  // typed, so a refusal naming either has nowhere to appear and belongs in the toast instead.
  const fields = useFieldErrors({
    only: [
      "from",
      "to",
      "period_start",
      "period_end",
      "cash_collected",
      "fees_charged",
      "net_amount",
      "reference",
    ],
  });
  const [form, setForm] = useState({ cash: "", fees: "", net: "", reference: "", orders: "" });

  const refresh = () =>
    void queryClient.invalidateQueries({
      queryKey: queryKeys.storeClients.settlements(store.uuid, filters),
    });

  const runPreview = useMutation({
    mutationFn: () => previewSettlement(store.uuid, from, to),
    onSuccess: (response) => {
      const row = response.Model?.totals?.[0] ?? null;
      setPreview(row);

      if (row) {
        setForm((current) => ({
          ...current,
          cash: String(row.cash_collected),
          fees: String(row.fees_charged),
          net: String(row.net_due_to_store),
          orders: String(row.delivered_count),
        }));
      }
    },
    onMutate: fields.reset,
    onError: (err) => {
      if (!fields.capture(err)) toast.error(friendlyErrorMessage(err, t));
    },
  });

  const create = useMutation({
    mutationFn: () =>
      createSettlement(store.uuid, {
        period_start: from,
        period_end: to,
        currency: preview?.currency ?? store.default_currency,
        cash_collected: Number(form.cash),
        fees_charged: Number(form.fees),
        net_amount: Number(form.net),
        orders_count: Number(form.orders || 0),
        reference: form.reference || null,
      }),
    onSuccess: () => {
      toast.success(t("settlements.created"));
      setOpen(false);
      setPreview(null);
      refresh();
    },
    onMutate: fields.reset,
    onError: (err) => {
      if (!fields.capture(err)) toast.error(friendlyErrorMessage(err, t));
    },
  });

  const settle = useMutation({
    mutationFn: (uuid: string) => settleSettlement(uuid),
    onSuccess: () => {
      toast.success(t("settlements.settled"));
      refresh();
    },
    onError: (err) => toast.error(friendlyErrorMessage(err, t)),
  });

  const cancel = useMutation({
    mutationFn: (uuid: string) => cancelSettlement(uuid),
    onSuccess: () => {
      toast.success(t("settlements.cancelled"));
      refresh();
    },
    onError: (err) => toast.error(friendlyErrorMessage(err, t)),
  });

  const settlements = data?.Model ?? [];
  // One box, two names for it depending on which of the two requests was refused.
  const fromError = fields.get("from") ?? fields.get("period_start");
  const toError = fields.get("to") ?? fields.get("period_end");

  return (
    <Card>
      <div className="flex flex-wrap items-start justify-between gap-3 border-b p-4">
        <div>
          <h3 className="text-sm font-semibold text-foreground">{t("settlements.title")}</h3>
          <p className="mt-1 text-xs text-muted-foreground">{t("settlements.subtitle")}</p>
        </div>
        {canManage ? (
          <Button size="sm" onClick={() => setOpen(true)}>
            <Calculator className="me-1 h-3 w-3" aria-hidden />
            {t("settlements.preview")}
          </Button>
        ) : null}
      </div>

      {isLoading ? (
        <TableSkeleton rows={4} cols={5} />
      ) : isError ? (
        <ErrorState message={friendlyErrorMessage(error, t)} onRetry={() => refetch()} />
      ) : settlements.length === 0 ? (
        <EmptyState
          title={t("settlements.empty")}
          description={t("settlements.emptyHint")}
          icon={HandCoins}
        />
      ) : (
        <div className="overflow-x-auto">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>{t("settlements.period")}</TableHead>
                <TableHead>{t("settlements.cashCollected")}</TableHead>
                <TableHead>{t("settlements.feesCharged")}</TableHead>
                <TableHead>{t("settlements.netAmount")}</TableHead>
                <TableHead>{t("common.status")}</TableHead>
                <TableHead aria-label={t("common.actions")} />
              </TableRow>
            </TableHeader>
            <TableBody>
              {settlements.map((row) => (
                <TableRow key={row.uuid}>
                  <TableCell className="text-sm">
                    {formatDate(row.period.from, locale)} — {formatDate(row.period.to, locale)}
                    {row.reference ? (
                      <p className="text-[0.7rem] text-muted-foreground">{row.reference}</p>
                    ) : null}
                  </TableCell>
                  <TableCell className="numeric">
                    {formatCurrency(row.cash_collected, row.currency, locale)}
                  </TableCell>
                  <TableCell className="numeric">
                    {formatCurrency(row.fees_charged, row.currency, locale)}
                  </TableCell>
                  <TableCell className="numeric font-medium">
                    {formatCurrency(row.net_amount, row.currency, locale)}
                  </TableCell>
                  <TableCell>
                    <div className="flex items-center gap-2">
                      <SettlementStatusBadge status={row.status} label={row.status_label} />
                      {row.status === "draft" ? (
                        <span
                          className="text-[0.7rem] text-muted-foreground"
                          title={t("settlements.draftHint")}
                        >
                          {t("settlements.draftHint")}
                        </span>
                      ) : null}
                    </div>
                  </TableCell>
                  <TableCell>
                    {/* Only a draft can move. A settled row is a record both sides hold. */}
                    {canManage && row.status === "draft" ? (
                      <div className="flex gap-1">
                        <Button
                          size="sm"
                          variant="ghost"
                          disabled={settle.isPending}
                          onClick={() => settle.mutate(row.uuid)}
                          title={t("settlements.settleBody")}
                        >
                          {t("settlements.settle")}
                        </Button>
                        <Button
                          size="sm"
                          variant="ghost"
                          onClick={() => setEditing(row)}
                        >
                          {t("settlements.edit")}
                        </Button>
                        <Button
                          size="sm"
                          variant="ghost"
                          disabled={cancel.isPending}
                          onClick={() => cancel.mutate(row.uuid)}
                        >
                          {t("common.cancel")}
                        </Button>
                      </div>
                    ) : null}
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </div>
      )}

      {/* Keyed on the draft: each open starts from that row's figures, not the previous one's. */}
      {editing ? (
        <EditSettlementDialog
          key={editing.uuid}
          settlement={editing}
          open
          onOpenChange={(next) => !next && setEditing(null)}
          onSaved={refresh}
        />
      ) : null}

      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t("settlements.preview")}</DialogTitle>
            <DialogDescription>{t("settlements.previewHint")}</DialogDescription>
          </DialogHeader>

          <div className="grid grid-cols-2 gap-3">
            <div className="space-y-1.5">
              <Label htmlFor="settlement-from">{t("settlements.from")}</Label>
              <Input
                id="settlement-from"
                type="date"
                value={from}
                onChange={(e) => setFrom(e.target.value)}
                aria-invalid={fromError !== undefined}
              />
              {fromError ? <p className="text-xs text-destructive">{fromError}</p> : null}
            </div>
            <div className="space-y-1.5">
              <Label htmlFor="settlement-to">{t("settlements.to")}</Label>
              <Input
                id="settlement-to"
                type="date"
                value={to}
                onChange={(e) => setTo(e.target.value)}
                aria-invalid={toError !== undefined}
              />
              {toError ? <p className="text-xs text-destructive">{toError}</p> : null}
            </div>
          </div>

          <Button
            variant="outline"
            onClick={() => runPreview.mutate()}
            disabled={runPreview.isPending || from === "" || to === ""}
          >
            {runPreview.isPending ? t("common.loading") : t("settlements.runPreview")}
          </Button>

          {preview ? (
            <div className="space-y-3 rounded-md bg-muted/40 p-3">
              <p className="text-xs text-muted-foreground">
                {preview.delivered_count} · {preview.currency}
              </p>

              <div className="grid grid-cols-3 gap-2">
                <NumberField
                  id="settlement-cash"
                  label={t("settlements.cashCollected")}
                  value={form.cash}
                  onChange={(value) => setForm({ ...form, cash: value })}
                  error={fields.get("cash_collected")}
                />
                <NumberField
                  id="settlement-fees"
                  label={t("settlements.feesCharged")}
                  value={form.fees}
                  onChange={(value) => setForm({ ...form, fees: value })}
                  error={fields.get("fees_charged")}
                />
                <NumberField
                  id="settlement-net"
                  label={t("settlements.netAmount")}
                  value={form.net}
                  onChange={(value) => setForm({ ...form, net: value })}
                  error={fields.get("net_amount")}
                />
              </div>
              <p className="text-xs text-muted-foreground">{t("settlements.netHint")}</p>

              <div className="space-y-1.5">
                <Label htmlFor="settlement-reference">{t("settlements.reference")}</Label>
                <Input
                  id="settlement-reference"
                  value={form.reference}
                  onChange={(e) => setForm({ ...form, reference: e.target.value })}
                  aria-invalid={fields.get("reference") !== undefined}
                />
                {fields.get("reference") ? (
                  <p className="text-xs text-destructive">{fields.get("reference")}</p>
                ) : null}
              </div>
            </div>
          ) : null}

          <DialogFooter>
            <Button variant="ghost" onClick={() => setOpen(false)}>
              {t("common.cancel")}
            </Button>
            <Button
              onClick={() => create.mutate()}
              disabled={create.isPending || preview === null}
            >
              {create.isPending ? t("common.saving") : t("settlements.createDraft")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </Card>
  );
}

function NumberField({
  id,
  label,
  value,
  error,
  onChange,
}: {
  id: string;
  label: string;
  value: string;
  /** The server's refusal for this figure, shown under it. */
  error?: string;
  onChange: (value: string) => void;
}) {
  return (
    <div className="space-y-1.5">
      <Label htmlFor={id} className="text-xs">
        {label}
      </Label>
      <Input
        id={id}
        type="number"
        step="0.01"
        value={value}
        aria-invalid={error !== undefined}
        onChange={(e) => onChange(e.target.value)}
      />
      {error ? <p className="text-xs text-destructive">{error}</p> : null}
    </div>
  );
}
