'use client';

import { useEffect, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { ChevronDown, ChevronRight, Plus, Trash2, Receipt } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { DatePicker } from '@/components/ui/date-picker';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetFooter,
} from '@/components/ui/sheet';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { PermissionGate } from '@/components/shared/permission-gate';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';

interface PaymentRow {
  id: string;
  paymentType: string;
  amount: string;
  currency: string;
  receivedAt: string;
  receiptFileId: string | null;
  notes: string | null;
  recordedBy: string;
  createdAt: string;
}

interface PaymentsResponse {
  data: {
    payments: PaymentRow[];
    depositTotal: { total: string; currency: string };
  };
}

const TYPE_LABELS: Record<string, string> = {
  deposit: 'Deposit',
  balance: 'Balance',
  refund: 'Refund',
  other: 'Other',
};

const TYPE_TINT: Record<string, string> = {
  deposit: 'bg-emerald-50 text-emerald-700 border-emerald-200',
  balance: 'bg-sky-50 text-sky-700 border-sky-200',
  refund: 'bg-rose-50 text-rose-700 border-rose-200',
  other: 'bg-slate-100 text-slate-700 border-slate-200',
};

function formatMoney(amount: string, currency: string): string {
  const n = Number(amount);
  if (!Number.isFinite(n)) return `${amount} ${currency}`;
  try {
    // `undefined` locale honours the user's browser locale. The
    // previous `'en-EU'` literal is not a valid BCP-47 tag - every
    // implementation falls back to the default anyway.
    return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(n);
  } catch {
    return `${n.toFixed(2)} ${currency}`;
  }
}

function formatDate(iso: string): string {
  return new Date(iso).toLocaleDateString();
}

/**
 * Per-interest collapse state. Persisted to localStorage so a rep
 * who collapses the section on one deal sees it stay collapsed when
 * they navigate away and back. Default collapsed (deposits are a
 * reference history once the rep stops actively recording them); the
 * "add a deposit" flow auto-expands so the new row is visible.
 */
function usePaymentsCollapsed(interestId: string): readonly [boolean, (v: boolean) => void] {
  const storageKey = `pn-crm.payments-collapsed.v1.${interestId}`;
  const [collapsed, setCollapsedState] = useState<boolean>(true);
  // Canonical client-only hydration pattern: server renders the default
  // (true), then on mount we read localStorage and reconcile. Initializing
  // useState() lazily from localStorage would risk a hydration mismatch
  // since the server has no access to the user's browser storage.
  useEffect(() => {
    try {
      const raw = window.localStorage.getItem(storageKey);
      // eslint-disable-next-line react-hooks/set-state-in-effect
      if (raw !== null) setCollapsedState(raw === '1');
    } catch {
      // ignore — localStorage may be unavailable in private mode
    }
  }, [storageKey]);
  function setCollapsed(v: boolean): void {
    setCollapsedState(v);
    try {
      window.localStorage.setItem(storageKey, v ? '1' : '0');
    } catch {
      // ignore
    }
  }
  return [collapsed, setCollapsed] as const;
}

export function PaymentsSection({
  interestId,
  depositExpectedAmount,
  depositExpectedCurrency,
}: {
  interestId: string;
  depositExpectedAmount: string | null;
  depositExpectedCurrency: string | null;
}) {
  const queryClient = useQueryClient();
  const [recordOpen, setRecordOpen] = useState(false);
  const [collapsed, setCollapsed] = usePaymentsCollapsed(interestId);

  const { data, isLoading } = useQuery<PaymentsResponse>({
    queryKey: ['interest-payments', interestId],
    queryFn: () => apiFetch(`/api/v1/interests/${interestId}/payments`),
  });

  const deleteMutation = useMutation({
    mutationFn: async (paymentId: string) =>
      apiFetch(`/api/v1/payments/${paymentId}`, { method: 'DELETE' }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['interest-payments', interestId] });
      queryClient.invalidateQueries({ queryKey: ['interests', interestId] });
    },
    onError: (err) => toastError(err),
  });

  if (isLoading) {
    return (
      <section className="rounded-lg border p-4 text-sm text-muted-foreground">
        Loading payments…
      </section>
    );
  }

  const payments = data?.data.payments ?? [];
  const total = data?.data.depositTotal;
  const expectedAmount = depositExpectedAmount ? Number(depositExpectedAmount) : null;
  const expectedCurrency = depositExpectedCurrency ?? 'EUR';
  const runningTotal = total ? Number(total.total) : 0;
  const remaining =
    expectedAmount !== null && Number.isFinite(expectedAmount)
      ? Math.max(0, expectedAmount - runningTotal)
      : null;

  // Collapsed summary bar — drops the full section to one line so the
  // milestone strip above gets the rep's primary visual focus. Click
  // anywhere on the bar (or the chevron) to expand inline.
  if (collapsed) {
    const summaryText =
      payments.length === 0
        ? 'Not received yet'
        : `${formatMoney(total?.total ?? '0', expectedCurrency)} received · ${payments.length} payment${payments.length === 1 ? '' : 's'}`;
    return (
      <>
        <button
          type="button"
          onClick={() => setCollapsed(false)}
          className="group flex w-full items-center justify-between gap-3 rounded-lg border bg-card/40 px-4 py-3 text-left transition-colors hover:bg-card/60"
          aria-expanded={false}
          aria-controls={`payments-section-${interestId}`}
        >
          <span className="flex items-center gap-2">
            <ChevronRight
              className="size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5"
              aria-hidden
            />
            <span className="text-sm font-semibold">Payments</span>
            <span className="text-xs text-muted-foreground">· {summaryText}</span>
          </span>
          <span className="text-xs text-muted-foreground">Expand</span>
        </button>
        <RecordPaymentSheet
          open={recordOpen}
          onOpenChange={setRecordOpen}
          interestId={interestId}
          defaultCurrency={expectedCurrency}
          onRecorded={() => setCollapsed(false)}
        />
      </>
    );
  }

  return (
    <section
      id={`payments-section-${interestId}`}
      className="rounded-lg border bg-card/40 p-4 space-y-3"
    >
      <div className="flex items-center justify-between gap-3">
        <div className="flex-1">
          <button
            type="button"
            onClick={() => setCollapsed(true)}
            className="group inline-flex items-center gap-2 text-left"
            aria-expanded={true}
            aria-controls={`payments-section-${interestId}`}
          >
            <ChevronDown
              className="size-4 text-muted-foreground transition-transform group-hover:translate-y-0.5"
              aria-hidden
            />
            <h3 className="text-sm font-semibold">Payments</h3>
          </button>
          <p className="mt-0.5 text-xs text-muted-foreground">
            Records that money was received or refunded. No invoices are issued - the bank handles
            that.
          </p>
        </div>
        <PermissionGate resource="payments" action="record">
          <Button size="sm" className="h-8 px-3 text-xs" onClick={() => setRecordOpen(true)}>
            <Plus className="size-3.5" aria-hidden />
            Record payment
          </Button>
        </PermissionGate>
      </div>

      {expectedAmount !== null ? (
        <div className="flex items-center justify-between rounded-md border border-border bg-muted/30 px-3 py-2 text-xs">
          <span>
            Expected deposit:{' '}
            <strong>{formatMoney(String(expectedAmount), expectedCurrency)}</strong>
          </span>
          <span>
            Received so far: <strong>{formatMoney(total?.total ?? '0', expectedCurrency)}</strong>
          </span>
          {remaining !== null ? (
            <span className={remaining === 0 ? 'text-emerald-700' : 'text-amber-700'}>
              {remaining === 0
                ? 'Fully received'
                : `${formatMoney(String(remaining), expectedCurrency)} outstanding`}
            </span>
          ) : null}
        </div>
      ) : null}

      {payments.length === 0 ? (
        <p className="rounded border border-dashed px-3 py-4 text-center text-xs text-muted-foreground">
          No payments recorded yet.
        </p>
      ) : (
        <ul className="divide-y divide-border rounded border">
          {payments.map((p) => (
            <li key={p.id} className="flex items-center justify-between gap-3 px-3 py-2">
              <div className="flex items-center gap-2.5">
                <span
                  className={`inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium ${
                    TYPE_TINT[p.paymentType] ?? TYPE_TINT.other
                  }`}
                >
                  {TYPE_LABELS[p.paymentType] ?? p.paymentType}
                </span>
                <div className="text-sm">
                  <span className="font-medium">{formatMoney(p.amount, p.currency)}</span>
                  <span className="ml-2 text-xs text-muted-foreground">
                    {formatDate(p.receivedAt)}
                  </span>
                  {p.notes ? (
                    <span className="ml-2 text-xs text-muted-foreground">· {p.notes}</span>
                  ) : null}
                </div>
                {p.receiptFileId ? (
                  <Receipt className="size-3 text-emerald-600" aria-hidden />
                ) : null}
              </div>
              <PermissionGate resource="payments" action="delete">
                <button
                  type="button"
                  aria-label="Delete payment record"
                  className="rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive"
                  disabled={deleteMutation.isPending}
                  onClick={() => {
                    if (confirm('Delete this payment record? This cannot be undone.')) {
                      deleteMutation.mutate(p.id);
                    }
                  }}
                >
                  <Trash2 className="size-3.5" aria-hidden />
                </button>
              </PermissionGate>
            </li>
          ))}
        </ul>
      )}

      <RecordPaymentSheet
        open={recordOpen}
        onOpenChange={setRecordOpen}
        interestId={interestId}
        defaultCurrency={expectedCurrency}
        onRecorded={() => setCollapsed(false)}
      />
    </section>
  );
}

function RecordPaymentSheet({
  open,
  onOpenChange,
  interestId,
  defaultCurrency,
  onRecorded,
}: {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  interestId: string;
  defaultCurrency: string;
  onRecorded?: () => void;
}) {
  const queryClient = useQueryClient();
  const [paymentType, setPaymentType] = useState<string>('deposit');
  const [amount, setAmount] = useState('');
  const [currency, setCurrency] = useState(defaultCurrency);
  const [receivedAt, setReceivedAt] = useState(() => {
    const today = new Date();
    return today.toISOString().slice(0, 10);
  });
  const [notes, setNotes] = useState('');
  const [acknowledgedNoReceipt, setAcknowledgedNoReceipt] = useState(false);

  const mutation = useMutation({
    mutationFn: async () =>
      apiFetch(`/api/v1/interests/${interestId}/payments`, {
        method: 'POST',
        body: {
          interestId,
          paymentType,
          amount,
          currency,
          receivedAt: new Date(receivedAt).toISOString(),
          notes: notes || null,
        },
      }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['interest-payments', interestId] });
      queryClient.invalidateQueries({ queryKey: ['interests', interestId] });
      onOpenChange(false);
      onRecorded?.();
      setAmount('');
      setNotes('');
      setAcknowledgedNoReceipt(false);
    },
    onError: (err) => toastError(err),
  });

  const canSubmit =
    amount.trim().length > 0 && receivedAt && acknowledgedNoReceipt && !mutation.isPending;

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent side="right" className="w-full overflow-y-auto sm:max-w-md">
        <SheetHeader>
          <SheetTitle>Record payment</SheetTitle>
          <SheetDescription>
            Capture that money was received (or refunded). Reps don&apos;t issue invoices - the bank
            does that - so this is just an audit record.
          </SheetDescription>
        </SheetHeader>

        <form
          className="mt-5 space-y-4"
          onSubmit={(e) => {
            e.preventDefault();
            mutation.mutate();
          }}
        >
          <div className="space-y-1.5">
            <Label htmlFor="payment-type">Type</Label>
            <Select value={paymentType} onValueChange={setPaymentType}>
              <SelectTrigger id="payment-type">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="deposit">Deposit</SelectItem>
                <SelectItem value="balance">Balance</SelectItem>
                <SelectItem value="refund">Refund</SelectItem>
                <SelectItem value="other">Other</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div className="grid grid-cols-[1fr_100px] gap-2">
            <div className="space-y-1.5">
              <Label htmlFor="payment-amount">Amount</Label>
              <Input
                id="payment-amount"
                type="number"
                step="0.01"
                min="0"
                placeholder="0.00"
                value={amount}
                onChange={(e) => setAmount(e.target.value)}
                required
              />
            </div>
            <div className="space-y-1.5">
              <Label htmlFor="payment-currency">Currency</Label>
              <Input
                id="payment-currency"
                value={currency}
                onChange={(e) => setCurrency(e.target.value.toUpperCase())}
                maxLength={3}
                required
              />
            </div>
          </div>

          <div className="space-y-1.5">
            <Label htmlFor="payment-date">Received on</Label>
            <DatePicker
              id="payment-date"
              value={receivedAt}
              onChange={setReceivedAt}
              toDate={new Date()}
              placeholder="Pick a date"
            />
          </div>

          <div className="space-y-1.5">
            <Label htmlFor="payment-notes">Notes (optional)</Label>
            <Input
              id="payment-notes"
              placeholder="Reference, payer name, etc."
              value={notes}
              onChange={(e) => setNotes(e.target.value)}
            />
          </div>

          <label className="flex items-start gap-2 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900">
            <input
              type="checkbox"
              checked={acknowledgedNoReceipt}
              onChange={(e) => setAcknowledgedNoReceipt(e.target.checked)}
              className="mt-0.5"
            />
            <span>
              I understand that recording a payment without an attached receipt may make later
              verification harder, and that the bank-issued receipt is the canonical proof.
            </span>
          </label>

          <SheetFooter className="gap-2">
            <Button
              type="button"
              variant="outline"
              onClick={() => onOpenChange(false)}
              disabled={mutation.isPending}
            >
              Cancel
            </Button>
            <Button type="submit" disabled={!canSubmit}>
              {mutation.isPending ? 'Saving…' : 'Record payment'}
            </Button>
          </SheetFooter>
        </form>
      </SheetContent>
    </Sheet>
  );
}
