import { useState, useRef, useTransition, useEffect } from 'react';
import { ArrowDown, ArrowUp, Clock, GripVertical, Pencil, TrendingUp, X } from 'lucide-react';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { toast } from 'sonner';
import { api } from '@/api';
import { cn, fmt, fmtDate, errMessage } from '@/lib/utils';
import { asDollars, type Dollars } from '@/lib/money';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import {
  TableRow, TableCell,
} from '@/components/ui/table';
import {
  AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle,
  AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,
} from '@/components/ui/alert-dialog';
import { paymentDateForTrackerMonth, paymentSummary, ROW_STATUS_CLS } from '@/lib/trackerUtils';
import { useQuickPay, useTogglePaid } from '@/hooks/usePaymentActions';
import { DEFAULT_TRACKER_TABLE_COLUMNS } from '@/lib/trackerTableColumns';
import { StatusBadge } from '@/components/tracker/StatusBadge';
import { PaymentProgress } from '@/components/tracker/PaymentProgress';
import { PaymentLedgerDialog } from '@/components/tracker/PaymentLedgerDialog';
import { NotesCell } from '@/components/tracker/NotesCell';
import { AutopaySuggestionActions } from '@/components/tracker/AutopaySuggestionActions';
import type { TrackerRow as TrackerRowData } from '@/types';
import type { DragProps, MoveControls, RowSelection } from '@/components/tracker/MobileTrackerRow';

// Cast type for the HTML5 drag handlers, which conflict with framer-motion's own
// onDrag* gesture types on the motion.tr-backed TableRow.
type TableRowDrag = React.ComponentProps<typeof TableRow>['onDragStart'];

interface TrackerRowProps {
  row: TrackerRowData;
  year: number;
  month: number;
  refresh: () => void;
  index: number;
  onEditBill?: (row: TrackerRowData) => void;
  moveControls?: MoveControls;
  dragProps?: DragProps;
  isDrifted?: boolean;
  visibleColumns?: string[];
  selection?: RowSelection;
}

export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveControls, dragProps, isDrifted, visibleColumns = DEFAULT_TRACKER_TABLE_COLUMNS, selection }: TrackerRowProps) {
  const amountRef                     = useRef<HTMLInputElement>(null);
  const [paymentLedgerOpen, setPaymentLedgerOpen] = useState(false);
  const [confirmUnpay, setConfirmUnpay] = useState(false);
  const [suggestionLoading, setSuggestionLoading] = useState(false);
  const [optimisticActual, setOptimisticActual] = useState<Dollars | undefined>(undefined);
  // Optimistic paid/unpaid flip: the row updates instantly on pay/skip and rolls
  // back on error. Cleared when real data arrives (see effect below).
  const [optimisticPaid, setOptimisticPaid] = useState<boolean | undefined>(undefined);
  const [showUpdateNudge, setShowUpdateNudge] = useState(false);
  const [nudgeAmount, setNudgeAmount] = useState<Dollars | null>(null);
  const [, startTransition] = useTransition();
  const quickPay = useQuickPay();
  const togglePaid = useTogglePaid(year, month);
  const visibleColumnSet = new Set(visibleColumns);
  const showColumn = (key: string) => visibleColumnSet.has(key);

  const [editingExpected, setEditingExpected] = useState(false);
  const [expectedDraft, setExpectedDraft] = useState('');
  const [editingDue, setEditingDue] = useState(false);
  const [dueDraft, setDueDraft] = useState('');

  // Effective amount threshold: optimistic override → monthly override → template default.
  const effectiveActual = optimisticActual !== undefined ? optimisticActual : row.actual_amount;
  const threshold = effectiveActual != null ? effectiveActual : row.expected_amount;
  const defaultPaymentDate = paymentDateForTrackerMonth(year, month, row.due_day);

  const isSkipped = !!row.is_skipped;
  const hasAutopaySuggestion = !!row.autopay_suggestion && !isSkipped;

  // Paid when total payments >= effective threshold
  const isPaidByThreshold = row.total_paid > 0 && row.total_paid >= threshold;
  const serverIsPaid = row.status === 'paid' || (row.status === 'autodraft' && !hasAutopaySuggestion) || isPaidByThreshold;
  const isPaid = optimisticPaid !== undefined ? optimisticPaid : serverIsPaid;
  const summary = paymentSummary(row, threshold);
  const bankPending = row.bank_pending_count ?? 0;

  // Effective status to show:
  // skipped > optimistic flip > paid (threshold-based) > backend status
  const effectiveStatus = isSkipped
    ? 'skipped'
    : optimisticPaid === true
      ? 'paid'
      : optimisticPaid === false
        ? row.status
        : (isPaidByThreshold && row.status !== 'paid' && row.status !== 'autodraft')
          ? 'paid'
          : row.status;

  // Drop the optimistic override once fresh server data for this row arrives.
  useEffect(() => {
    setOptimisticPaid(undefined);
  }, [row.status, row.total_paid, row.actual_amount]);

  const rowBg = isSkipped ? '' : (ROW_STATUS_CLS[effectiveStatus] || '');

  function handleQuickPay() {
    const val = parseFloat(amountRef.current?.value ?? '');
    if (!val || val <= 0) { toast.error('Enter a payment amount'); return; }
    quickPay.run(row, asDollars(val), defaultPaymentDate);
  }

  function performTogglePaid() {
    togglePaid.run(row, { wasPaid: isPaid, threshold, setOptimisticPaid });
  }

  function handleTogglePaid() {
    if (isPaid) {
      setConfirmUnpay(true);
      return;
    }
    performTogglePaid();
  }

  function handleRowKeyDown(e: React.KeyboardEvent<HTMLTableRowElement>) {
    // Only act on the row element itself, not on interactive children
    if (e.target !== e.currentTarget) return;

    switch (e.key) {
      case 'ArrowDown':
      case 'j': {
        e.preventDefault();
        const all = [...document.querySelectorAll<HTMLElement>('[data-tracker-row]')];
        const next = all[all.indexOf(e.currentTarget) + 1];
        next?.focus();
        break;
      }
      case 'ArrowUp':
      case 'k': {
        e.preventDefault();
        const all = [...document.querySelectorAll<HTMLElement>('[data-tracker-row]')];
        const prev = all[all.indexOf(e.currentTarget) - 1];
        prev?.focus();
        break;
      }
      case 'Enter': {
        e.preventDefault();
        onEditBill?.(row);
        break;
      }
      case 'p':
      case 'P': {
        if (e.ctrlKey || e.metaKey) break; // don't intercept Ctrl+P (print)
        e.preventDefault();
        if (!isSkipped) handleTogglePaid();
        break;
      }
      case 'Escape': {
        e.currentTarget.blur();
        break;
      }
      default:
        break;
    }
  }

  async function handleMarkFullAmount() {
    const newActual = summary.paidTowardDue;
    setOptimisticActual(newActual);
    try {
      await api.saveBillMonthlyState(row.id, {
        year, month,
        actual_amount: newActual,
        notes: row.monthly_notes || null,
        is_skipped: row.is_skipped,
      });
      setNudgeAmount(newActual);
      setShowUpdateNudge(true);
      refresh?.();
    } catch (err) {
      setOptimisticActual(undefined);
      toast.error(errMessage(err, 'Failed to update amount'));
    }
  }

  function handleUpdateTemplate() {
    const amount = nudgeAmount;
    setShowUpdateNudge(false);
    startTransition(async () => {
      try {
        await api.updateBill(row.id, { name: row.name, due_day: row.due_day, expected_amount: amount });
        toast.success(`Default updated to ${fmt(amount)}`);
        refresh?.();
      } catch (err) {
        toast.error(errMessage(err, 'Failed to update default'));
      }
    });
  }

  async function handleApplySuggestion(amount: Dollars) {
    setOptimisticActual(amount);
    try {
      await api.saveBillMonthlyState(row.id, {
        year, month,
        actual_amount: amount,
        notes: row.monthly_notes || null,
        is_skipped: row.is_skipped,
      });
      refresh?.();
    } catch (err) {
      setOptimisticActual(undefined);
      toast.error(errMessage(err, 'Failed to apply suggestion'));
    }
  }

  async function handleSaveExpected() {
    setEditingExpected(false);
    const val = parseFloat(expectedDraft);
    if (!isFinite(val) || val < 0) return;
    const current = effectiveActual ?? row.expected_amount;
    if (val === current) return;

    if (effectiveActual != null) {
      setOptimisticActual(asDollars(val));
      try {
        await api.saveBillMonthlyState(row.id, {
          year, month,
          actual_amount: val,
          notes: row.monthly_notes || null,
          is_skipped: row.is_skipped,
        });
        refresh?.();
      } catch (err) {
        setOptimisticActual(undefined);
        toast.error(errMessage(err, 'Failed to update amount'));
      }
    } else {
      try {
        await api.updateBill(row.id, { name: row.name, due_day: row.due_day, expected_amount: val });
        refresh?.();
      } catch (err) {
        toast.error(errMessage(err, 'Failed to update expected amount'));
      }
    }
  }

  async function handleSaveDue() {
    setEditingDue(false);
    const day = parseInt(dueDraft, 10);
    if (!isFinite(day) || day < 1 || day > 31) return;
    if (day === row.due_day) return;
    try {
      await api.updateBill(row.id, { name: row.name, due_day: day, expected_amount: row.expected_amount });
      refresh?.();
    } catch (err) {
      toast.error(errMessage(err, 'Failed to update due date'));
    }
  }

  async function handleConfirmSuggestion() {
    setSuggestionLoading(true);
    try {
      const result = await api.confirmAutopaySuggestion(row.id, { year, month }) as { created?: boolean };
      toast.success(result.created ? 'Autopay payment confirmed' : 'Autopay already recorded');
      refresh?.();
    } catch (err) {
      toast.error(errMessage(err, 'Failed to confirm autopay suggestion'));
    } finally {
      setSuggestionLoading(false);
    }
  }

  async function handleDismissSuggestion() {
    setSuggestionLoading(true);
    try {
      await api.dismissAutopaySuggestion(row.id, { year, month });
      toast.success('Autopay suggestion dismissed');
      refresh?.();
    } catch (err) {
      toast.error(errMessage(err, 'Failed to dismiss autopay suggestion'));
    } finally {
      setSuggestionLoading(false);
    }
  }

  return (
    <>
      <TableRow
        layout="position"
        transition={{ layout: { duration: 0.2, ease: [0.22, 1, 0.36, 1] } }}
        data-tracker-row
        tabIndex={0}
        aria-rowindex={index + 1}
        aria-label={`${row.name}, ${effectiveStatus}, ${row.due_day ? `due ${row.due_day}` : ''}`}
        onKeyDown={handleRowKeyDown}
        draggable={dragProps?.draggable}
        onDragStart={dragProps?.onDragStart as TableRowDrag}
        onDragEnter={dragProps?.onDragEnter}
        onDragOver={dragProps?.onDragOver}
        onDragEnd={dragProps?.onDragEnd as TableRowDrag}
        onDrop={dragProps?.onDrop}
        className={cn(
          'group border-border/65 transition-colors duration-150',
          'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 focus-visible:ring-inset',
          isSkipped ? 'opacity-40' : 'hover:bg-accent/50',
          rowBg,
          dragProps?.isDragging && 'opacity-45',
          dragProps?.isDropTarget && 'ring-2 ring-inset ring-primary/35',
        )}
        style={{ animationDelay: `${index * 40}ms` }}
      >
        {/* Bill name + category + monthly notes (if set) */}
        <TableCell className="w-[18%] py-2.5">
          <div className="flex min-w-0 items-center gap-2.5">
            {selection && (
              <Checkbox
                checked={selection.selected}
                onCheckedChange={(v) => selection.onToggle(v === true)}
                aria-label={`Select ${row.name}`}
                className="shrink-0"
              />
            )}
            <div className="flex shrink-0 items-center gap-0.5">
              <GripVertical
                className={cn(
                  'h-3.5 w-3.5 text-muted-foreground/55',
                  moveControls?.enabled && 'cursor-grab group-active:cursor-grabbing',
                  !moveControls?.enabled && 'opacity-30',
                )}
                aria-hidden="true"
              />
              <div className="hidden flex-col sm:flex">
                <button
                  type="button"
                  onClick={moveControls?.onMoveUp}
                  disabled={!moveControls?.enabled || !moveControls?.canMoveUp || moveControls?.moving}
                  className="rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-25"
                  title="Move bill up"
                  aria-label={`Move ${row.name} up`}
                >
                  <ArrowUp className="h-3 w-3" />
                </button>
                <button
                  type="button"
                  onClick={moveControls?.onMoveDown}
                  disabled={!moveControls?.enabled || !moveControls?.canMoveDown || moveControls?.moving}
                  className="rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-25"
                  title="Move bill down"
                  aria-label={`Move ${row.name} down`}
                >
                  <ArrowDown className="h-3 w-3" />
                </button>
              </div>
            </div>
            <div className="min-w-0">
              <div className="flex min-w-0 items-center gap-1.5">
                {row.website ? (
                  <a
                    href={row.website}
                    target="_blank"
                    rel="noreferrer"
                    className={cn(
                      'min-w-0 truncate text-sm font-semibold leading-tight text-foreground transition-colors',
                      'hover:underline decoration-muted-foreground/50 underline-offset-2',
                      isSkipped && 'line-through',
                    )}
                  >
                    {row.name}
                  </a>
                ) : (
                  <span className={cn('min-w-0 truncate text-sm font-semibold leading-tight text-foreground', isSkipped && 'line-through')}>
                    {row.name}
                  </span>
                )}
                <TooltipProvider delayDuration={300}>
                  {row.autopay_enabled && (() => {
                    const stats = row.autopay_stats;
                    const hasFailed = !!(stats && stats.failures > 0);
                    const verifiedAt = row.autopay_verified_at ? new Date(row.autopay_verified_at) : null;
                    const daysSinceVerify = verifiedAt
                      ? Math.floor((Date.now() - verifiedAt.getTime()) / 86400000)
                      : null;
                    const needsVerify = daysSinceVerify === null || daysSinceVerify > 90;
                    const badgeCls = hasFailed
                      ? 'border-amber-500/40 bg-amber-500/15 text-amber-600 dark:text-amber-300'
                      : 'border-sky-500/25 bg-sky-500/10 text-sky-600 dark:text-sky-300';
                    return (
                      <Tooltip>
                        <TooltipTrigger asChild>
                          <span className={cn('inline-flex shrink-0 items-center gap-0.5 rounded border px-1.5 py-0.5 text-[10px] font-bold leading-none cursor-default', badgeCls)}>
                            {hasFailed ? '⚠' : null}AP
                            {needsVerify && <Clock className="h-2.5 w-2.5 ml-0.5 opacity-70" />}
                          </span>
                        </TooltipTrigger>
                        <TooltipContent className="max-w-[220px] space-y-1">
                          {stats && stats.total > 0 ? (
                            <p className={cn('font-semibold', hasFailed ? 'text-amber-300' : 'text-emerald-300')}>
                              {hasFailed ? '⚠' : '✓'} {stats.total - stats.failures}/{stats.total} on time (12mo)
                            </p>
                          ) : (
                            <p className="font-semibold">Autopay enabled</p>
                          )}
                          {hasFailed && stats?.last_failure_date && (
                            <p className="text-xs opacity-80">Last failed: {stats.last_failure_date}</p>
                          )}
                          {hasFailed && stats?.last_failure_notes && (
                            <p className="text-xs opacity-70 italic">{stats.last_failure_notes}</p>
                          )}
                          {needsVerify ? (
                            <p className="text-xs opacity-70">
                              {daysSinceVerify === null ? 'Never verified — confirm it\'s still active' : `Verified ${daysSinceVerify}d ago — check soon`}
                            </p>
                          ) : (
                            <p className="text-xs opacity-70">Verified {daysSinceVerify}d ago</p>
                          )}
                        </TooltipContent>
                      </Tooltip>
                    );
                  })()}
                  {(row.has_merchant_rule || row.has_linked_transactions) && (
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <span className="inline-flex shrink-0 rounded border border-emerald-500/25 bg-emerald-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-emerald-600 dark:text-emerald-400 cursor-default">
                          L
                        </span>
                      </TooltipTrigger>
                      <TooltipContent>Linked to bank transactions</TooltipContent>
                    </Tooltip>
                  )}
                  {row.is_subscription && (
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <span className="inline-flex shrink-0 rounded border border-indigo-500/25 bg-indigo-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-indigo-600 dark:text-indigo-300 cursor-default">
                          S
                        </span>
                      </TooltipTrigger>
                      <TooltipContent>Subscription</TooltipContent>
                    </Tooltip>
                  )}
                </TooltipProvider>
                <Button
                  size="icon" variant="ghost"
                  className="h-6 w-6 shrink-0 opacity-100 transition-opacity text-muted-foreground hover:text-foreground hover:bg-accent lg:opacity-0 lg:group-hover:opacity-100"
                  title="Edit bill"
                  aria-label={`Edit ${row.name}`}
                  onClick={() => onEditBill?.(row)}
                >
                  <Pencil className="h-3 w-3" />
                </Button>
              </div>
              {row.category_name && (
                <p className="mt-0.5 truncate text-[11px] font-medium leading-none text-muted-foreground/75">{row.category_name}</p>
              )}
              {/* Monthly notes shown inline under the bill name */}
              {row.monthly_notes && (
                <p className="text-[11px] text-amber-500/80 mt-0.5 italic truncate max-w-[140px]"
                  title={row.monthly_notes}>
                  {row.monthly_notes}
                </p>
              )}
            </div>
          </div>
        </TableCell>

        {/* Due */}
        {showColumn('due') && (
          <TableCell className="tracker-number w-[10%] py-2.5 text-[13px] font-medium text-foreground/75">
            {editingDue ? (
              <input
                type="number"
                min="1" max="31"
                value={dueDraft}
                autoFocus
                onChange={e => setDueDraft(e.target.value)}
                onBlur={handleSaveDue}
                onKeyDown={e => {
                  if (e.key === 'Enter') e.currentTarget.blur();
                  if (e.key === 'Escape') { setEditingDue(false); }
                }}
                className="tracker-number w-12 rounded border border-border bg-transparent px-1 py-0.5 text-sm font-medium text-foreground outline-none focus:ring-[2px] focus:ring-ring/50"
                title="Day of month (1–31)"
              />
            ) : (
              <button
                type="button"
                onClick={() => { setDueDraft(String(row.due_day)); setEditingDue(true); }}
                className="rounded px-1 py-0.5 transition-colors hover:bg-accent hover:text-foreground"
                title="Click to edit due day"
              >
                {fmtDate(row.due_date)}
              </button>
            )}
          </TableCell>
        )}

        {/* Expected / Actual — shows actual_amount in amber when it overrides the template */}
        {showColumn('expected') && (
          <TableCell className="tracker-number w-[10%] py-2.5 text-center text-[13px] font-semibold">
            {editingExpected ? (
              <input
                type="number"
                min="0" step="0.01"
                value={expectedDraft}
                autoFocus
                onChange={e => setExpectedDraft(e.target.value)}
                onBlur={handleSaveExpected}
                onKeyDown={e => {
                  if (e.key === 'Enter') e.currentTarget.blur();
                  if (e.key === 'Escape') { setEditingExpected(false); }
                }}
                className="tracker-number mx-auto w-24 rounded border border-border bg-transparent px-1 py-0.5 text-center text-sm font-semibold text-foreground outline-none focus:ring-[2px] focus:ring-ring/50"
              />
            ) : effectiveActual != null ? (
              <button
                type="button"
                onClick={() => { setExpectedDraft(String(effectiveActual)); setEditingExpected(true); }}
                className="mx-auto rounded px-1 py-0.5 text-amber-300 transition-colors hover:bg-accent"
                title={`Monthly override — click to edit. Template default: ${fmt(row.expected_amount)}`}
              >
                {fmt(effectiveActual)}
              </button>
            ) : (
              <div className="mx-auto flex w-[68px] flex-col items-center gap-0.5">
                <button
                  type="button"
                  onClick={() => { setExpectedDraft(String(row.expected_amount)); setEditingExpected(true); }}
                  className="rounded px-1 py-0.5 text-center text-foreground/85 transition-colors hover:bg-accent hover:text-foreground"
                  title="Click to edit expected amount"
                >
                  {fmt(row.expected_amount)}
                </button>
                {isDrifted && (
                  <span className="inline-flex items-center gap-0.5 text-[10px] font-semibold text-amber-500">
                    <TrendingUp className="h-2.5 w-2.5" />Changed
                  </span>
                )}
                {row.sparkline && row.sparkline.length >= 2 && (() => {
                  const vals = row.sparkline;
                  const min = Math.min(...vals);
                  const max = Math.max(...vals);
                  const range = max - min || 1;
                  const W = 40, H = 12;
                  const pts = vals.map((v, i) => {
                    const x = (i / (vals.length - 1)) * W;
                    const y = H - ((v - min) / range) * H;
                    return `${x.toFixed(1)},${y.toFixed(1)}`;
                  }).join(' ');
                  return (
                    <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} className="opacity-50">
                      <polyline points={pts} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" />
                    </svg>
                  );
                })()}
                {row.amount_suggestion?.suggestion != null &&
                 Math.abs(row.amount_suggestion.suggestion - row.expected_amount) / row.expected_amount > 0.05 && (
                  <button
                    type="button"
                    onClick={() => handleApplySuggestion(row.amount_suggestion!.suggestion)}
                    className="text-[10px] text-muted-foreground/50 transition-colors hover:text-muted-foreground"
                    title={`Based on last ${row.amount_suggestion.months_used} months`}
                  >
                    ~{fmt(row.amount_suggestion.suggestion)}
                  </button>
                )}
              </div>
            )}
          </TableCell>
        )}

        {/* Previous month paid */}
        {showColumn('previous') && (
          <TableCell className="tracker-number w-[10%] py-2.5 text-center text-[13px] font-medium text-muted-foreground/80">
            {row.previous_month_paid > 0 ? fmt(row.previous_month_paid) : '—'}
          </TableCell>
        )}

        {/* Amount paid — mismatch now compares against threshold */}
        {showColumn('paid') && (
          <TableCell className="w-[10%] py-2.5 text-center">
            <PaymentProgress
              row={row}
              threshold={threshold}
              className="mx-auto max-w-[7.5rem]"
              onOpen={() => setPaymentLedgerOpen(true)}
              onMarkFullAmount={!isSkipped ? handleMarkFullAmount : undefined}
            />
          </TableCell>
        )}

        {/* Paid date */}
        {showColumn('paid_date') && (
          <TableCell className="w-[10%] py-2.5 text-[13px] text-foreground/75">
            <button
              type="button"
              onClick={() => setPaymentLedgerOpen(true)}
              className="tracker-number rounded-md px-1.5 py-0.5 font-medium transition-colors hover:bg-accent hover:text-foreground"
              title="View payment history"
            >
              {row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}
              {summary.count > 1 && <span className="ml-1 text-[10px] text-muted-foreground">({summary.count})</span>}
            </button>
          </TableCell>
        )}

        {/* Status — uses effectiveStatus (accounts for skipped + threshold) */}
        {showColumn('status') && (
          <TableCell className="w-[9%] py-2.5">
            <div className="flex flex-col items-center gap-1">
              {bankPending > 0 ? (
                <span
                  className="inline-flex items-center rounded-full border border-emerald-400/40 bg-emerald-500/10 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-emerald-600 dark:text-emerald-400"
                  title={`Bank has ${bankPending} pending charge${bankPending > 1 ? 's' : ''} matching this bill`}
                >
                  Pending
                </span>
              ) : row.pending_cleared ? (
                <span
                  className="inline-flex items-center rounded-full border border-amber-400/40 bg-amber-500/10 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-amber-600 dark:text-amber-400"
                  title="Paid in tracker but may not have cleared your bank account yet"
                >
                  Pending
                </span>
              ) : (
                <StatusBadge
                  status={effectiveStatus}
                  clickable
                  onClick={() => {
                    if (effectiveStatus === 'skipped') return;
                    handleTogglePaid();
                  }}
                  loading={togglePaid.isPending}
                />
              )}
            </div>
          </TableCell>
        )}

        {/* Actions */}
        {showColumn('action') && (
          <TableCell className="w-[10%] py-2.5 text-center">
            <div className="flex items-center justify-center gap-1">
              {showUpdateNudge ? (
                <div className="flex items-center gap-1 animate-in fade-in slide-in-from-right-1 duration-200">
                  <span className="text-[10px] text-muted-foreground">Update default?</span>
                  <Button
                    size="sm" variant="ghost"
                    onClick={handleUpdateTemplate}
                    className="h-6 px-2 text-[10px] font-semibold text-emerald-600 hover:bg-emerald-500/10 hover:text-emerald-700 dark:text-emerald-400 dark:hover:text-emerald-300"
                  >
                    {fmt(nudgeAmount)}
                  </Button>
                  <button
                    type="button"
                    onClick={() => setShowUpdateNudge(false)}
                    className="text-muted-foreground transition-colors hover:text-foreground"
                    title="Dismiss"
                  >
                    <X className="h-3 w-3" />
                  </button>
                </div>
              ) : (
                <>
                  {hasAutopaySuggestion && (
                    <AutopaySuggestionActions
                      row={row}
                      loading={suggestionLoading}
                      onConfirm={handleConfirmSuggestion}
                      onDismiss={handleDismissSuggestion}
                    />
                  )}
                  {/* Quick pay — hidden for skipped/paid bills */}
                  {!isPaid && !isSkipped && !hasAutopaySuggestion && (
                    <div className="flex items-center gap-1">
                      <Input
                        ref={amountRef}
                        type="number" min="0" step="0.01"
                        defaultValue={summary.remaining || threshold}
                        className="tracker-number h-7 w-20 text-right text-sm font-medium bg-background/50 border-border/50"
                        title="Payment amount"
                      />
                      <Button
                        size="sm" variant="ghost"
                        onClick={handleQuickPay}
                        className="h-7 px-2.5 text-xs font-semibold text-emerald-600 hover:text-emerald-700 hover:bg-emerald-50 dark:text-emerald-400 dark:hover:text-emerald-300 dark:hover:bg-emerald-500/10"
                      >
                        Add
                      </Button>
                    </div>
                  )}
                </>
              )}
            </div>
          </TableCell>
        )}

        {/* Notes cell (monthly state notes) */}
        {showColumn('notes') && (
          <TableCell className="w-[23%] py-2.5 border-l border-border pl-4">
            <NotesCell row={{ ...row, year, month }} refresh={refresh} />
          </TableCell>
        )}
      </TableRow>

      {paymentLedgerOpen && (
        <PaymentLedgerDialog
          row={row}
          year={year}
          month={month}
          threshold={threshold}
          defaultPaymentDate={defaultPaymentDate}
          onClose={() => setPaymentLedgerOpen(false)}
          onSaved={refresh}
        />
      )}

      <AlertDialog open={confirmUnpay} onOpenChange={setConfirmUnpay}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Mark this bill unpaid?</AlertDialogTitle>
            <AlertDialogDescription>
              This removes the current payment record for this month and moves it into recovery.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={togglePaid.isPending}>Cancel</AlertDialogCancel>
            <AlertDialogAction
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
              disabled={togglePaid.isPending}
              onClick={performTogglePaid}
            >
              {togglePaid.isPending ? 'Removing...' : 'Remove Payment'}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
}
