import { useState, useRef, useEffect } from 'react';
import { motion } from 'framer-motion';
import { ArrowDown, ArrowUp, GripVertical, Pencil, TrendingUp } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api';
import { cn, fmt, fmtDate, errMessage } from '@/lib/utils';
import { asDollars } from '@/lib/money';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
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 { StatusBadge } from '@/components/tracker/StatusBadge';
import { PaymentProgress } from '@/components/tracker/PaymentProgress';
import { LowerThisMonthButton } from '@/components/tracker/LowerThisMonthButton';
import { PaymentLedgerDialog } from '@/components/tracker/PaymentLedgerDialog';
import { NotesCell } from '@/components/tracker/NotesCell';
import { AutopaySuggestionActions } from '@/components/tracker/AutopaySuggestionActions';
import type { TrackerRow } from '@/types';

function MiniSparkline({ values }: { values?: number[] | null }) {
  if (!values || values.length < 2) return null;
  const min = Math.min(...values);
  const max = Math.max(...values);
  const range = max - min || 1;
  const width = 44;
  const height = 14;
  const points = values.map((value, index) => {
    const x = (index / (values.length - 1)) * width;
    const y = height - ((value - min) / range) * height;
    return `${x.toFixed(1)},${y.toFixed(1)}`;
  }).join(' ');

  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} className="mt-1 opacity-60" aria-hidden="true">
      <polyline points={points} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" />
    </svg>
  );
}

// HTML5 drag-and-drop wiring supplied by the parent bucket. Cast onto motion.div
// (framer-motion redefines its own onDrag* gesture handlers, which conflict).
export interface DragProps {
  draggable?: boolean;
  onDragStart?: React.DragEventHandler<HTMLDivElement>;
  onDragEnter?: React.DragEventHandler<HTMLDivElement>;
  onDragOver?: React.DragEventHandler<HTMLDivElement>;
  onDragEnd?: React.DragEventHandler<HTMLDivElement>;
  onDrop?: React.DragEventHandler<HTMLDivElement>;
  isDragging?: boolean;
  isDropTarget?: boolean;
}

export interface MoveControls {
  enabled?: boolean;
  onMoveUp?: () => void;
  onMoveDown?: () => void;
  canMoveUp?: boolean;
  canMoveDown?: boolean;
  moving?: boolean;
}

// Per-row multi-select state supplied by the bucket. When present, the row shows
// a leading checkbox that adds/removes it from the page-level selection.
export interface RowSelection {
  selected: boolean;
  onToggle: (next: boolean) => void;
}

interface MobileTrackerRowProps {
  row: TrackerRow;
  year: number;
  month: number;
  refresh: () => void;
  index: number;
  onEditBill?: (row: TrackerRow) => void;
  moveControls?: MoveControls;
  dragProps?: DragProps;
  isDrifted?: boolean;
  selection?: RowSelection;
}

export function MobileTrackerRow({ row, year, month, refresh, index, onEditBill, moveControls, dragProps, isDrifted = false, selection }: MobileTrackerRowProps) {
  const amountRef                     = useRef<HTMLInputElement>(null);
  const [paymentLedgerOpen, setPaymentLedgerOpen] = useState(false);
  const [confirmUnpay, setConfirmUnpay] = useState(false);
  const [suggestionLoading, setSuggestionLoading] = useState(false);
  const quickPay = useQuickPay();
  const togglePaid = useTogglePaid(year, month);
  // Optimistic paid/unpaid flip — instant on tap, rolled back on error, cleared
  // when fresh server data arrives (effect below).
  const [optimisticPaid, setOptimisticPaid] = useState<boolean | undefined>(undefined);

  const threshold = row.actual_amount != null ? row.actual_amount : row.expected_amount;
  const defaultPaymentDate = paymentDateForTrackerMonth(year, month, row.due_day);
  const isSkipped = !!row.is_skipped;
  const hasAutopaySuggestion = !!row.autopay_suggestion && !isSkipped;
  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 effectiveStatus = isSkipped
    ? 'skipped'
    : optimisticPaid === true
      ? 'paid'
      : optimisticPaid === false
        ? row.status
        : (isPaidByThreshold && row.status !== 'paid' && row.status !== 'autodraft')
          ? 'paid'
          : row.status;

  useEffect(() => {
    setOptimisticPaid(undefined);
  }, [row.status, row.total_paid, row.actual_amount]);
  const rowBg = isSkipped ? '' : (ROW_STATUS_CLS[effectiveStatus] || '');
  const remaining = Math.max((threshold || 0) - (row.total_paid || 0), 0);
  const summary = paymentSummary(row, threshold);

  function handleQuickPay() {
    if (quickPay.isPending) return;
    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();
  }

  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 (
    <>
      <motion.div
        layout="position"
        transition={{ layout: { duration: 0.2, ease: [0.22, 1, 0.36, 1] } }}
        draggable={dragProps?.draggable}
        onDragStart={dragProps?.onDragStart as React.ComponentProps<typeof motion.div>['onDragStart']}
        onDragEnter={dragProps?.onDragEnter}
        onDragOver={dragProps?.onDragOver}
        onDragEnd={dragProps?.onDragEnd as React.ComponentProps<typeof motion.div>['onDragEnd']}
        onDrop={dragProps?.onDrop}
        className={cn(
          'rounded-lg border border-border/60 bg-background/60 p-3 shadow-sm',
          'space-y-3 transition-colors',
          isSkipped ? 'opacity-55' : rowBg,
          dragProps?.isDragging && 'opacity-45',
          dragProps?.isDropTarget && 'ring-2 ring-primary/40',
        )}
        style={{ animationDelay: `${index * 40}ms` }}
      >
        <div className="flex min-w-0 items-start justify-between gap-3">
          <div className="flex min-w-0 gap-2">
            {selection && (
              <div className="flex shrink-0 items-center pt-0.5">
                <Checkbox
                  checked={selection.selected}
                  onCheckedChange={(v) => selection.onToggle(v === true)}
                  aria-label={`Select ${row.name}`}
                />
              </div>
            )}
            <div className="flex shrink-0 items-center gap-0.5 pt-0.5">
              <GripVertical
                className={cn(
                  'h-4 w-4 text-muted-foreground/55',
                  moveControls?.enabled && 'cursor-grab',
                  !moveControls?.enabled && 'opacity-30',
                )}
                aria-hidden="true"
              />
              <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 className="min-w-0">
            <div className="flex min-w-0 items-center gap-2">
              {row.website ? (
                <a
                  href={row.website}
                  target="_blank"
                  rel="noreferrer"
                  className={cn(
                    'min-w-0 truncate text-[15px] font-semibold leading-tight text-foreground',
                    'underline-offset-2 transition-colors hover:text-primary hover:underline',
                    isSkipped && 'line-through',
                  )}
                >
                  {row.name}
                </a>
              ) : (
                <span className={cn('min-w-0 truncate text-[15px] font-semibold leading-tight text-foreground', isSkipped && 'line-through')}>
                  {row.name}
                </span>
              )}
              {row.autopay_enabled && (
                <span
                  className="inline-flex shrink-0 rounded border border-sky-500/25 bg-sky-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-sky-600 dark:text-sky-300"
                  title="Autopay"
                >
                  AP
                </span>
              )}
              {(row.has_merchant_rule || row.has_linked_transactions) && (
                <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"
                  title="Linked to bank transactions"
                >
                  L
                </span>
              )}
              {row.is_subscription && (
                <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"
                  title="Subscription"
                >
                  S
                </span>
              )}
              <Button
                size="icon" variant="ghost"
                className="h-7 w-7 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.monthly_notes && (
              <p className="mt-1 line-clamp-2 text-xs italic text-amber-500/80" title={row.monthly_notes}>
                {row.monthly_notes}
              </p>
            )}
            </div>
          </div>
          <StatusBadge status={effectiveStatus} clickable={!isSkipped} onClick={handleTogglePaid} />
        </div>

        <div className="grid grid-cols-2 gap-x-3 gap-y-2 text-xs text-muted-foreground sm:grid-cols-4">
          <div>
            <p className="uppercase tracking-wide text-muted-foreground/60">Due</p>
            <p className="tracker-number mt-0.5 text-sm font-medium text-foreground/90">{fmtDate(row.due_date)}</p>
          </div>
          <div>
            <p className="uppercase tracking-wide text-muted-foreground/60">Category</p>
            <p className="mt-0.5 truncate text-sm text-foreground">{row.category_name || 'Uncategorized'}</p>
          </div>
          <div>
            <p className="uppercase tracking-wide text-muted-foreground/60">Expected</p>
            <p className={cn('tracker-number mt-0.5 text-sm font-semibold', row.actual_amount != null ? 'text-amber-300' : 'text-foreground')}>
              {fmt(threshold)}
            </p>
            {isDrifted && (
              <span className="mt-0.5 inline-flex items-center gap-0.5 text-[10px] font-semibold text-amber-500">
                <TrendingUp className="h-2.5 w-2.5" />
                Changed
              </span>
            )}
            <MiniSparkline values={row.sparkline} />
          </div>
          <div>
            <p className="uppercase tracking-wide text-muted-foreground/60">Last Month</p>
            <p className="tracker-number mt-0.5 text-sm font-medium text-muted-foreground/80">
              {fmt(row.previous_month_paid)}
            </p>
          </div>
          <div>
            <p className="uppercase tracking-wide text-muted-foreground/60">Remaining</p>
            <p className={cn('tracker-number mt-0.5 text-sm font-semibold', remaining > 0 ? 'text-foreground' : 'text-emerald-300')}>
              {fmt(asDollars(remaining))}
            </p>
          </div>
        </div>

        <div className="rounded-md border border-border/50 bg-muted/20">
          <PaymentProgress row={row} threshold={threshold} onOpen={() => setPaymentLedgerOpen(true)} compact />
        </div>

        <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
          <div className="grid grid-cols-2 gap-2 text-xs sm:flex sm:items-center">
            <div className="rounded-md bg-muted/45 px-2 py-1.5">
              <span className="text-muted-foreground">Paid </span>
              <span className="tracker-number font-semibold text-emerald-300">{row.total_paid > 0 ? fmt(row.total_paid) : '—'}</span>
            </div>
            <div className="rounded-md bg-muted/45 px-2 py-1.5">
              <span className="text-muted-foreground">Date </span>
              <button
                type="button"
                onClick={() => setPaymentLedgerOpen(true)}
                className="tracker-number rounded font-medium text-foreground underline-offset-2 hover:underline"
              >
                {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>
            </div>
          </div>

          <div className="flex flex-wrap items-center justify-end gap-1.5">
            {hasAutopaySuggestion && (
              <AutopaySuggestionActions
                row={row}
                loading={suggestionLoading}
                onConfirm={handleConfirmSuggestion}
                onDismiss={handleDismissSuggestion}
                compact
              />
            )}
            {!isPaid && !isSkipped && !hasAutopaySuggestion && (
              <div className="flex items-center gap-1.5">
                <Input
                  ref={amountRef}
                  type="number" min="0" step="0.01"
                  defaultValue={summary.remaining || threshold}
                  className="tracker-number h-8 w-24 text-right text-sm font-medium bg-background/70 border-border/60"
                  title="Payment amount"
                  aria-label={`${row.name} payment amount`}
                  disabled={quickPay.isPending}
                />
                <Button
                  size="sm" variant="default"
                  onClick={handleQuickPay}
                  disabled={quickPay.isPending}
                  className="h-8 px-3 text-xs font-semibold"
                >
                  {quickPay.isPending ? 'Adding...' : 'Add'}
                </Button>
              </div>
            )}
            <LowerThisMonthButton
              row={row}
              year={year}
              month={month}
              refresh={refresh}
              compact
            />

          </div>
        </div>

        <div className="rounded-md border border-border/50 bg-muted/25 px-2 py-1.5">
          <NotesCell row={{ ...row, year, month }} refresh={refresh} />
        </div>
      </motion.div>

      {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>Cancel</AlertDialogCancel>
            <AlertDialogAction
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
              onClick={performTogglePaid}
            >
              Remove Payment
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
}
