import { router, useForm } from '@inertiajs/react';
import { AlertTriangle, CheckCircle2, Copy, ExternalLink, Link2, RefreshCw, Unplug } from 'lucide-react';
import { useEffect, useState } from 'react';
import { PageHeader } from '@/components/PageHeader';
import { SettingsNav } from '@/components/SettingsNav';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardBody, CardHeader } from '@/components/ui/card';
import { Checkbox } from '@/components/ui/checkbox';
import { Select } from '@/components/ui/input';
import { Field } from '@/components/ui/label';
import AppLayout from '@/layouts/AppLayout';
import { dateTime } from '@/lib/format';
import { http, HttpError } from '@/lib/http';
import { cn } from '@/lib/utils';

type Sync = { id: number; entity: string; label: string; status: string; error: string | null; warning: string | null; qbo_id: string | null; qbo_number: string | null; attempts: number; at: string | null; url: string | null };
type Props = {
    company: { id: number; name: string; prefix: string };
    qbo: {
        configured: boolean; sandbox: boolean; connected: boolean; company_name: string | null; realm_id: string | null; connected_at: string | null; error: string | null;
        refresh_expires_at: string | null; settings: { invoice_on_accept: boolean; estimate_on_accept: boolean; gst_code: string | null; gst_free_code: string | null; income_account: string | null }; redirect: string;
    };
    log: Sync[];
    logFilter: 'all' | 'failed';
    canEdit: boolean;
};
type Options = { tax_codes: { id: string; name: string; description: string | null }[]; income_accounts: { id: string; name: string }[] };

function CopyText({ value, testId }: { value: string; testId?: string }) {
    const [done, setDone] = useState(false);
    return (
        <span className="flex min-w-0 items-center gap-1.5">
            <code className="min-w-0 flex-1 break-all rounded bg-stone-100 px-1.5 py-0.5 text-xs" data-testid={testId}>{value}</code>
            <button type="button" className="shrink-0 rounded p-1 text-ink-muted hover:bg-stone-100" aria-label="Copy" onClick={() => { navigator.clipboard?.writeText(value); setDone(true); setTimeout(() => setDone(false), 1500); }}>
                {done ? <CheckCircle2 className="h-3.5 w-3.5 text-green-700" /> : <Copy className="h-3.5 w-3.5" />}
            </button>
        </span>
    );
}

const ENTITY: Record<string, string> = { customer: 'Customer', item: 'Product / service', invoice: 'Invoice', estimate: 'Estimate' };

export default function QuickBooksSettings({ company, qbo, log, logFilter, canEdit }: Props) {
    return (
        <AppLayout title="QuickBooks">
            <PageHeader title="QuickBooks" breadcrumbs={[{ label: 'Settings', href: '/settings/company' }, { label: 'QuickBooks' }]}
                description={`QuickBooks Online for ${company.name}. Each company connects its own QuickBooks company; clients pay on the invoice QuickBooks sends.`} />
            <SettingsNav />
            <div className="grid max-w-4xl gap-6">
                <ConnectionCard company={company} qbo={qbo} canEdit={canEdit} />
                {qbo.connected && <SyncLog log={log} filter={logFilter} canEdit={canEdit} />}
            </div>
        </AppLayout>
    );
}

function ConnectionCard({ company, qbo, canEdit }: Pick<Props, 'company' | 'qbo' | 'canEdit'>) {
    const [opts, setOpts] = useState<Options | null>(null);
    const [optErr, setOptErr] = useState<string | null>(null);
    const form = useForm({ invoice_on_accept: qbo.settings.invoice_on_accept ?? true, estimate_on_accept: qbo.settings.estimate_on_accept, gst_code: qbo.settings.gst_code ?? '', gst_free_code: qbo.settings.gst_free_code ?? '', income_account: qbo.settings.income_account ?? '' });
    useEffect(() => {
        if (!qbo.connected || qbo.error || !canEdit) return;
        http<Options>('GET', '/settings/quickbooks/options').then(setOpts).catch((e) => setOptErr(e instanceof HttpError ? e.message : 'Couldn’t load the QuickBooks lists.'));
    }, [qbo.connected, qbo.error, canEdit]);
    const connect = () => router.post('/settings/quickbooks/connect');
    const disconnect = () => { if (window.confirm(`Disconnect QuickBooks from ${company.name}? Nothing in QuickBooks is changed.`)) router.delete('/settings/quickbooks', { preserveScroll: true }); };

    return (
        <Card data-testid="qbo-card">
            <CardHeader title="QuickBooks Online" description="Clients and items sync to QuickBooks, and “Complete & Invoice” creates the invoice there. Send it from QuickBooks so the client can pay it."
                actions={qbo.connected ? (qbo.error ? <Badge className="bg-red-100 text-red-800">Reconnect needed</Badge> : <Badge className="bg-green-100 text-green-800">Connected{qbo.sandbox ? ' · sandbox' : ''}</Badge>) : <Badge className="bg-stone-100 text-ink-muted">Not connected</Badge>} />
            <CardBody className="space-y-5">
                {!qbo.configured ? (
                    <div className="rounded-md border border-amber-300 bg-amber-50 px-3 py-2.5 text-sm text-amber-900" data-testid="qbo-not-configured">
                        <p className="font-medium">One-time setup on the server</p>
                        <p className="mt-1">Create an app at developer.intuit.com (Accounting scope), add this redirect URI, then put its keys in the server’s .env as <code>QBO_CLIENT_ID</code> and <code>QBO_CLIENT_SECRET</code>:</p>
                        <div className="mt-2"><CopyText value={qbo.redirect} /></div>
                    </div>
                ) : qbo.connected ? (
                    <>
                        <div className="flex flex-wrap items-center gap-3 rounded-md border border-line bg-stone-50 px-3 py-2 text-sm" data-testid="qbo-connection">
                            <Link2 className="h-4 w-4 text-ink-muted" aria-hidden />
                            <span className="min-w-0 flex-1">Connected to <b>{qbo.company_name ?? `QuickBooks company ${qbo.realm_id}`}</b>{qbo.connected_at ? ` on ${dateTime(qbo.connected_at)}` : ''}.</span>
                            {canEdit && <Button type="button" size="sm" variant="ghost" onClick={disconnect}><Unplug className="h-4 w-4" /> Disconnect</Button>}
                        </div>
                        {qbo.error && (
                            <div role="alert" className="flex flex-wrap items-center gap-3 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800" data-testid="qbo-reconnect">
                                <AlertTriangle className="h-4 w-4" /> <span className="min-w-0 flex-1">{qbo.error}</span>
                                {canEdit && <Button type="button" size="sm" onClick={connect}>Reconnect</Button>}
                            </div>
                        )}
                        <form onSubmit={(e) => { e.preventDefault(); form.put('/settings/quickbooks', { preserveScroll: true }); }} className="space-y-4">
                            <fieldset disabled={!canEdit} className="space-y-4">
                                {optErr && <p className="text-sm text-red-700">{optErr}</p>}
                                <div className="grid gap-4 sm:grid-cols-2">
                                    <Field label="GST on sales (items with 10% GST)" htmlFor="qbo-gst">
                                        <Select id="qbo-gst" value={form.data.gst_code} onChange={(e) => form.setData('gst_code', e.target.value)}>
                                            <option value="">{opts ? 'Choose…' : 'Loading…'}</option>
                                            {opts?.tax_codes.map((c) => <option key={c.id} value={c.id}>{c.name}{c.description ? ` · ${c.description}` : ''}</option>)}
                                        </Select>
                                    </Field>
                                    <Field label="GST free (items with 0% tax)" htmlFor="qbo-free">
                                        <Select id="qbo-free" value={form.data.gst_free_code} onChange={(e) => form.setData('gst_free_code', e.target.value)}>
                                            <option value="">{opts ? 'Choose…' : 'Loading…'}</option>
                                            {opts?.tax_codes.map((c) => <option key={c.id} value={c.id}>{c.name}{c.description ? ` · ${c.description}` : ''}</option>)}
                                        </Select>
                                    </Field>
                                    <Field label="Income account for new products / services" htmlFor="qbo-income">
                                        <Select id="qbo-income" value={form.data.income_account} onChange={(e) => form.setData('income_account', e.target.value)}>
                                            <option value="">{opts ? 'Choose…' : 'Loading…'}</option>
                                            {opts?.income_accounts.map((a) => <option key={a.id} value={a.id}>{a.name}</option>)}
                                        </Select>
                                    </Field>
                                </div>
                                <Checkbox label="Create the invoice in QuickBooks automatically when a quote is accepted" checked={form.data.invoice_on_accept} onChange={(e) => form.setData('invoice_on_accept', e.target.checked)} data-testid="qbo-invoice-on-accept" />
                                {!form.data.invoice_on_accept && <Checkbox label="Create a QuickBooks estimate when a quote is accepted instead" checked={form.data.estimate_on_accept} onChange={(e) => form.setData('estimate_on_accept', e.target.checked)} />}
                                <p className="text-xs text-ink-muted">Invoices are created unsent (QuickBooks has no drafts) {form.data.invoice_on_accept ? 'as soon as the client accepts (or you record their acceptance), and the quote moves to Invoiced' : <>when a quote is marked <b>Invoiced</b></>}, from the lines the client chose plus anything added after acceptance. Review and send them from QuickBooks.</p>
                            </fieldset>
                            {canEdit && (
                                <div className="flex flex-wrap justify-end gap-2">
                                    <Button type="button" variant="secondary" onClick={() => router.post('/settings/quickbooks/sync', {}, { preserveScroll: true })} data-testid="qbo-sync-all"><RefreshCw className="h-4 w-4" /> Sync contacts &amp; items now</Button>
                                    <Button type="submit" disabled={form.processing}>Save</Button>
                                </div>
                            )}
                        </form>
                    </>
                ) : (
                    <div className="flex flex-wrap items-center gap-3">
                        <p className="min-w-0 flex-1 text-sm text-ink-muted">Connect {company.name}’s own QuickBooks Online company. You’ll sign in to Intuit and choose the company.</p>
                        {canEdit && <Button type="button" onClick={connect} data-testid="qbo-connect"><Link2 className="h-4 w-4" /> Connect QuickBooks</Button>}
                    </div>
                )}
            </CardBody>
        </Card>
    );
}

function SyncLog({ log, filter, canEdit }: { log: Sync[]; filter: 'all' | 'failed'; canEdit: boolean }) {
    return (
        <Card data-testid="qbo-log">
            <CardHeader title="Sync log" description="Everything sent to QuickBooks. Failed items retry automatically a few times; use Retry once the problem is fixed."
                actions={
                    <div className="inline-flex rounded-md border border-line p-0.5 text-xs">
                        {(['all', 'failed'] as const).map((f) => (
                            <button key={f} type="button" aria-pressed={filter === f} onClick={() => router.get('/settings/quickbooks', f === 'failed' ? { log: 'failed' } : {}, { preserveScroll: true, preserveState: true })}
                                className={cn('rounded px-2.5 py-1', filter === f ? 'bg-ink text-white' : 'text-ink-muted hover:bg-stone-100')}>{f === 'all' ? 'All' : 'Failed'}</button>
                        ))}
                    </div>
                } />
            <CardBody className="p-0">
                {log.length === 0 ? <p className="px-5 py-6 text-sm text-ink-muted">Nothing synced yet.</p> : (
                    <table className="w-full text-sm">
                        <thead className="text-left text-xs text-ink-muted"><tr><th className="px-5 py-2 font-medium">What</th><th className="px-3 py-2 font-medium">Status</th><th className="px-3 py-2 font-medium">When</th><th className="px-5 py-2" /></tr></thead>
                        <tbody>
                            {log.map((s) => (
                                <tr key={s.id} className="border-t border-line align-top" data-testid={`sync-${s.id}`}>
                                    <td className="px-5 py-2.5">
                                        <div className="text-xs text-ink-muted">{ENTITY[s.entity] ?? s.entity}</div>
                                        <div className="font-medium">{s.label}{s.qbo_number ? ` → ${s.qbo_number}` : ''}</div>
                                        {s.error && <div className="mt-0.5 text-xs text-red-700">{s.error}</div>}
                                        {s.warning && <div className="mt-0.5 text-xs text-amber-800">{s.warning}</div>}
                                    </td>
                                    <td className="px-3 py-2.5">
                                        <Badge className={s.status === 'ok' ? 'bg-green-100 text-green-800' : s.status === 'failed' ? 'bg-red-100 text-red-800' : 'bg-stone-100 text-ink-muted'}>{s.status === 'ok' ? 'Synced' : s.status === 'failed' ? `Failed${s.attempts > 1 ? ` ×${s.attempts}` : ''}` : 'Pending'}</Badge>
                                    </td>
                                    <td className="whitespace-nowrap px-3 py-2.5 text-xs text-ink-muted">{s.at ? dateTime(s.at) : '—'}</td>
                                    <td className="whitespace-nowrap px-5 py-2.5 text-right">
                                        {s.url && <a href={s.url} target="_blank" rel="noreferrer" className="mr-2 inline-flex items-center gap-1 text-xs text-link underline">Open <ExternalLink className="h-3 w-3" /></a>}
                                        {canEdit && s.status === 'failed' && <Button type="button" size="sm" variant="secondary" onClick={() => router.post(`/settings/quickbooks/log/${s.id}/retry`, {}, { preserveScroll: true })}>Retry</Button>}
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                )}
            </CardBody>
        </Card>
    );
}
