import { AlertTriangle, ExternalLink, FileText, Loader2, RefreshCw } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Card, CardBody, CardHeader } from '@/components/ui/card';
import { http, HttpError } from '@/lib/http';

type Doc = { status: string; number: string | null; error: string | null; warning: string | null; at: string | null; url: string | null; sync_id: number; created_at?: string | null; total_cents?: number | null; currency?: string;
    qbo?: { state: string; sent?: boolean; sent_at?: string | null; balance_cents?: number; due_date?: string | null; checked_at?: string } | null; check_error?: string | null } | null;

const STATES: Record<string, [string, string]> = {
    unsent: ['Not sent yet', 'bg-slate-100 text-slate-700'],
    sent: ['Sent', 'bg-sky-100 text-sky-800'],
    partial: ['Part paid', 'bg-amber-100 text-amber-800'],
    overdue: ['Overdue', 'bg-red-100 text-red-800'],
    paid: ['Paid', 'bg-emerald-100 text-emerald-800'],
    voided: ['Voided', 'bg-slate-200 text-slate-700'],
    deleted: ['Deleted in QuickBooks', 'bg-slate-200 text-slate-700'],
    accepted: ['Accepted', 'bg-emerald-100 text-emerald-800'],
    closed: ['Closed', 'bg-slate-200 text-slate-700'],
    rejected: ['Rejected', 'bg-red-100 text-red-800'],
};
const day = (d: string) => new Date(`${d}T00:00:00`).toLocaleDateString('en-AU', { day: 'numeric', month: 'short', year: 'numeric' });

const when = (iso: string) => new Date(iso).toLocaleString('en-AU', { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: 'Australia/Sydney' });
const money = (cents: number, cur = 'AUD') => new Intl.NumberFormat('en-AU', { style: 'currency', currency: cur }).format(cents / 100);
type Data = { connected: boolean; error: string | null; invoice: Doc; estimate: Doc; can_invoice: boolean };

/** Quote editor: the quote's QuickBooks invoice / estimate (the client pays the invoice sent from QuickBooks). */
export function QuickBooksCard({ quoteId, companyId, status, refreshKey }: { quoteId: number; companyId: number; status: string; refreshKey: number }) {
    const [data, setData] = useState<Data | null>(null);
    const [busy, setBusy] = useState<string | null>(null);
    const [msg, setMsg] = useState<string | null>(null);
    const h = { 'X-Company': String(companyId) };
    const load = (refresh = false) => http<Data>('GET', `/quotes/${quoteId}/quickbooks${refresh ? '?refresh=1' : ''}`, undefined, h).then(setData).catch(() => {});
    const [checking, setChecking] = useState(false);
    const recheck = async () => { setChecking(true); try { await load(true); } finally { setChecking(false); } };
    useEffect(() => { void load(); }, [quoteId, status, refreshKey]); // eslint-disable-line react-hooks/exhaustive-deps
    // While something is on its way to QuickBooks, check back every few seconds.
    const pending = data && [data.invoice, data.estimate].some((d) => d?.status === 'pending');
    useEffect(() => { if (!pending) return; const t = window.setInterval(() => void load(), 4000); return () => window.clearInterval(t); }, [pending]); // eslint-disable-line react-hooks/exhaustive-deps

    if (!data?.connected) return null;
    const sync = async (kind: 'invoice' | 'estimate') => {
        setBusy(kind); setMsg(null);
        try { const r = await http<{ message: string }>('POST', `/quotes/${quoteId}/quickbooks/${kind}`, {}, h); setMsg(r.message); await load(); }
        catch (e) { setMsg(e instanceof HttpError ? e.message : 'Couldn’t reach QuickBooks.'); }
        finally { setBusy(null); }
    };
    const doc = (label: string, d: Doc, kind: 'invoice' | 'estimate') => d && (
        <div className="rounded-md border border-line px-3 py-2 text-sm" data-testid={`qbo-${kind}`}>
            <div className="flex items-center gap-2">
                <FileText className="h-4 w-4 text-ink-muted" aria-hidden />
                <span className="min-w-0 flex-1 font-medium">{d.status === 'ok' ? label : d.status === 'pending' ? `${label} being created in QuickBooks…` : `QuickBooks ${label.toLowerCase()} failed`}</span>
                {d.status === 'ok' && d.qbo && STATES[d.qbo.state] && (
                    <span className={`rounded-full px-2 py-0.5 text-xs font-medium ${STATES[d.qbo.state][1]}`} data-testid={`qbo-${kind}-state`}>{STATES[d.qbo.state][0]}</span>
                )}
                {d.url && <a href={d.url} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 text-xs text-link underline">Open <ExternalLink className="h-3 w-3" /></a>}
                {d.status === 'failed' && <Button type="button" size="sm" variant="secondary" onClick={() => void sync(kind)} disabled={!!busy}><RefreshCw className="h-3.5 w-3.5" /> Retry</Button>}
            </div>
            {d.status === 'ok' && (
                <dl className="mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-0.5 text-xs">
                    <dt className="text-ink-muted">{label} number</dt>
                    <dd className="font-semibold text-ink" data-testid={`qbo-${kind}-number`}>{d.number ?? 'Not numbered in QuickBooks'}</dd>
                    {d.total_cents != null && <><dt className="text-ink-muted">Amount</dt><dd>{money(d.total_cents, d.currency)}</dd></>}
                    {d.created_at && <><dt className="text-ink-muted">Created</dt><dd>{when(d.created_at)}</dd></>}
                    {d.qbo && d.qbo.state !== 'deleted' && d.qbo.state !== 'voided' && (
                        <><dt className="text-ink-muted">Sent to client</dt>
                            <dd data-testid={`qbo-${kind}-sent`}>{d.qbo.sent ? (d.qbo.sent_at ? when(d.qbo.sent_at) : 'Yes') : 'Not yet'}</dd></>
                    )}
                    {kind === 'invoice' && d.qbo && d.qbo.balance_cents != null && ['partial', 'overdue', 'sent', 'unsent'].includes(d.qbo.state) && d.qbo.balance_cents !== d.total_cents && (
                        <><dt className="text-ink-muted">Balance due</dt><dd>{money(d.qbo.balance_cents, d.currency)}</dd></>
                    )}
                    {d.qbo?.due_date && ['sent', 'unsent', 'partial', 'overdue'].includes(d.qbo.state) && (
                        <><dt className="text-ink-muted">{kind === 'invoice' ? 'Due' : 'Expires'}</dt><dd className={d.qbo.state === 'overdue' ? 'font-medium text-red-700' : ''}>{day(d.qbo.due_date)}</dd></>
                    )}
                </dl>
            )}
            {d.error && <p className="mt-1 text-xs text-red-700">{d.error}</p>}
            {d.warning && <p className="mt-1 text-xs text-amber-800">{d.warning}</p>}
            {kind === 'invoice' && d.status === 'ok' && (!d.qbo || d.qbo.state === 'unsent') && <p className="mt-1 text-xs text-ink-muted">Created unsent: open it in QuickBooks to send it to the client for payment.</p>}
            {d.check_error && <p className="mt-1 text-xs text-amber-800">Couldn’t check the latest status: {d.check_error}</p>}
            {d.status === 'ok' && (
                <p className="mt-1 flex items-center gap-1.5 text-[11px] text-ink-muted">
                    {d.qbo?.checked_at ? `Checked ${when(d.qbo.checked_at)}` : 'Not checked yet'}
                    <button type="button" className="inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-link underline" onClick={() => void recheck()} disabled={checking} data-testid={`qbo-${kind}-recheck`}>
                        {checking ? <Loader2 className="h-3 w-3 animate-spin" /> : <RefreshCw className="h-3 w-3" />} Check now
                    </button>
                </p>
            )}
        </div>
    );

    return (
        <Card data-testid="quickbooks-card">
            <CardHeader title="QuickBooks" />
            <CardBody className="space-y-2">
                {data.error && <p className="flex gap-1.5 text-xs text-red-700"><AlertTriangle className="h-3.5 w-3.5 shrink-0" /> {data.error}</p>}
                {doc('Invoice', data.invoice, 'invoice')}
                {doc('Estimate', data.estimate, 'estimate')}
                {!data.invoice && data.can_invoice && (
                    <Button type="button" size="sm" variant="secondary" className="w-full" onClick={() => void sync('invoice')} disabled={!!busy} data-testid="create-qbo-invoice">
                        {busy === 'invoice' ? <Loader2 className="h-4 w-4 animate-spin" /> : <FileText className="h-4 w-4" />} Create QuickBooks invoice
                    </Button>
                )}
                {!data.invoice && !data.can_invoice && <p className="text-xs text-ink-muted">The invoice is created in QuickBooks when the quote is accepted (or marked Invoiced, if automatic invoicing is off in Settings → QuickBooks).</p>}
                {msg && <p className="text-xs text-ink-muted" role="status">{msg}</p>}
            </CardBody>
        </Card>
    );
}
