import { useMutation } from '@tanstack/react-query';
import { toast } from 'sonner';
import { api } from '@/api';
import { fmt, errMessage } from '@/lib/utils';
import type { Dollars } from '@/lib/money';
import { useInvalidateTrackerData } from '@/hooks/useQueries';

/** The bits of a tracker row these payment actions need. */
interface PayableRow {
  id: number;
  name: string;
}

// Quick-pay a tracker row (record a payment for `val` on `paidDate`) with a
// reversible Undo toast. A React Query mutation: `isPending` comes for free and
// the tracker/badge caches are invalidated on settle. Shared by the desktop and
// mobile tracker rows so the flow lives in one place.
export function useQuickPay() {
  const invalidate = useInvalidateTrackerData();
  const mutation = useMutation({
    mutationFn: (payload: { bill_id: number; amount: number; paid_date: string }) => api.quickPay(payload),
    onSettled: () => invalidate(),
  });

  const run = (row: PayableRow, val: Dollars, paidDate: string) => mutation.mutate(
    { bill_id: row.id, amount: val, paid_date: paidDate },
    {
      onSuccess: (payment) => {
        toast.success(`${row.name} — ${fmt(val)} paid`, {
          action: {
            label: 'Undo',
            onClick: async () => {
              try {
                await api.deletePayment(payment.id);
                toast.success('Payment removed');
                invalidate();
              } catch (err) {
                toast.error(errMessage(err, 'Failed to undo payment.'));
              }
            },
          },
        });
      },
      onError: (err) => toast.error(errMessage(err, 'Failed to add payment.')),
    },
  );

  return { run, isPending: mutation.isPending };
}

interface TogglePaidOptions {
  wasPaid: boolean;
  threshold: Dollars;
  setOptimisticPaid: (value: boolean | undefined) => void;
}

// Toggle a tracker row paid/unpaid. The caller owns the instant optimistic flip
// (its local `setOptimisticPaid`) so the row updates immediately; this hook rolls
// it back on error, invalidates the tracker/badge caches on settle, and shows the
// right toast (an Undo when un-paying, a specific "paid" message otherwise).
// Shared by the desktop and mobile tracker rows.
export function useTogglePaid(year: number, month: number) {
  const invalidate = useInvalidateTrackerData();
  const mutation = useMutation({
    mutationFn: ({ rowId, amount }: { rowId: number; amount: number | undefined }) =>
      api.togglePaid(rowId, { amount, year, month }),
    onSettled: () => invalidate(),
  });

  const run = (row: PayableRow, { wasPaid, threshold, setOptimisticPaid }: TogglePaidOptions) => {
    setOptimisticPaid(!wasPaid); // instant flip; effect/rollback reconciles
    mutation.mutate(
      { rowId: row.id, amount: wasPaid ? undefined : threshold },
      {
        onSuccess: (result) => {
          if (wasPaid && result.paymentId) {
            const paymentId = result.paymentId; // capture the narrowed id for the deferred Undo closure
            toast.success('Payment moved to recovery', {
              action: {
                label: 'Undo',
                onClick: async () => {
                  try {
                    await api.restorePayment(paymentId);
                    toast.success('Payment restored');
                    invalidate();
                  } catch (err) {
                    toast.error(errMessage(err, 'Failed to restore payment'));
                  }
                },
              },
            });
          } else if (!wasPaid) {
            toast.success(`${row.name} — ${fmt(threshold)} paid`);
          }
        },
        onError: (err) => {
          setOptimisticPaid(undefined); // roll back the instant flip
          toast.error(errMessage(err, 'Failed to toggle payment status'));
        },
      },
    );
  };

  return { run, isPending: mutation.isPending };
}
