import { useRef, useState } from 'react';
import { toast } from 'sonner';
import { FileText, Upload, Loader2, CheckCircle2, X } from 'lucide-react';
import { api } from '@/api';
import { cn, errMessage } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { formatCentsUSD, type Cents } from '@/lib/money';
import { SectionCard, importErrorState, type SectionCardProps } from './dataShared';

interface OfxTx {
  payee?: string | null;
  description?: string | null;
  posted_date?: string | null;
  amount: Cents;
}

interface OfxPreview {
  import_session_id?: string;
  count: number;
  sample?: OfxTx[];
}

/**
 * Import bank transactions from an OFX / QFX file. Unlike CSV, the file is
 * structured, so there is no column-mapping step: upload → preview → import.
 * Duplicates are skipped by the server (same dedupe scope as CSV/SimpleFIN).
 */
export default function ImportOfxSection({ onHistoryRefresh, cardProps = {} }: {
  onHistoryRefresh?: () => void;
  cardProps?: Partial<SectionCardProps>;
}) {
  const fileRef = useRef<HTMLInputElement>(null);
  const [preview, setPreview] = useState<OfxPreview | null>(null);
  const [busy, setBusy] = useState<'preview' | 'commit' | null>(null);

  async function handleFile(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    setBusy('preview');
    setPreview(null);
    try {
      setPreview(await api.previewOfxTransactionImport(file) as OfxPreview);
    } catch (err) {
      toast.error(importErrorState(err, 'Could not read that OFX/QFX file.').message);
    } finally {
      setBusy(null);
      if (fileRef.current) fileRef.current.value = '';
    }
  }

  async function handleImport() {
    if (!preview?.import_session_id) return;
    setBusy('commit');
    try {
      const r = await api.commitOfxTransactionImport({ import_session_id: preview.import_session_id }) as { imported?: number; skipped?: number; failed?: number };
      const parts = [`${r.imported ?? 0} imported`];
      if (r.skipped) parts.push(`${r.skipped} already present`);
      if (r.failed) parts.push(`${r.failed} failed`);
      toast.success(`OFX import complete — ${parts.join(', ')}.`);
      setPreview(null);
      onHistoryRefresh?.();
    } catch (err) {
      toast.error(errMessage(err, 'OFX import failed.'));
    } finally {
      setBusy(null);
    }
  }

  return (
    <SectionCard {...cardProps}>
      <div className="space-y-4 px-6 py-5">
        <div className="rounded-lg border border-border/60 bg-muted/25 p-4">
          <div className="flex items-start gap-3">
            <FileText className="mt-0.5 h-5 w-5 shrink-0 text-primary" />
            <p className="min-w-0 text-sm text-muted-foreground">
              Many banks export <span className="font-medium text-foreground">.ofx</span> or{' '}
              <span className="font-medium text-foreground">.qfx</span> files. Upload one to import its
              transactions — duplicates are skipped automatically.
            </p>
          </div>
        </div>

        {!preview ? (
          <div>
            <input
              ref={fileRef}
              id="ofx-upload"
              type="file"
              accept=".ofx,.qfx,application/x-ofx"
              className="hidden"
              onChange={handleFile}
              disabled={busy === 'preview'}
            />
            <label htmlFor="ofx-upload">
              <Button asChild variant="outline" className="cursor-pointer gap-2">
                <span>
                  {busy === 'preview' ? <Loader2 className="h-4 w-4 animate-spin" /> : <Upload className="h-4 w-4" />}
                  {busy === 'preview' ? 'Reading…' : 'Choose .ofx / .qfx file'}
                </span>
              </Button>
            </label>
          </div>
        ) : (
          <div className="space-y-3">
            <div className="flex items-center justify-between gap-2">
              <p className="text-sm font-medium text-foreground">
                <CheckCircle2 className="mr-1.5 inline h-4 w-4 text-emerald-500" />
                {preview.count} transaction{preview.count === 1 ? '' : 's'} found
              </p>
              <Button variant="ghost" size="sm" className="gap-1 text-xs" onClick={() => setPreview(null)} disabled={busy === 'commit'}>
                <X className="h-3.5 w-3.5" /> Cancel
              </Button>
            </div>
            <ul className="max-h-56 divide-y divide-border/50 overflow-y-auto rounded-lg border border-border/50">
              {(preview.sample || []).map((tx, i) => (
                <li key={i} className="flex items-center justify-between gap-3 px-3 py-2 text-sm">
                  <span className="min-w-0 flex-1 truncate">{tx.payee || tx.description || 'Transaction'}</span>
                  <span className="shrink-0 text-xs text-muted-foreground tabular-nums">{tx.posted_date}</span>
                  <span className={cn('shrink-0 tabular-nums', tx.amount < 0 ? 'text-foreground' : 'text-emerald-600 dark:text-emerald-400')}>
                    {formatCentsUSD(tx.amount, { signed: true })}
                  </span>
                </li>
              ))}
              {preview.count > (preview.sample || []).length && (
                <li className="px-3 py-2 text-center text-xs text-muted-foreground">
                  + {preview.count - (preview.sample || []).length} more
                </li>
              )}
            </ul>
            <Button className="gap-2" onClick={handleImport} disabled={busy === 'commit'}>
              {busy === 'commit' ? <Loader2 className="h-4 w-4 animate-spin" /> : <Upload className="h-4 w-4" />}
              Import {preview.count} transaction{preview.count === 1 ? '' : 's'}
            </Button>
          </div>
        )}
      </div>
    </SectionCard>
  );
}
