import { router, useForm } from '@inertiajs/react';
import { AlertTriangle, Bug, CheckCircle2, ChevronDown, ChevronRight, Clipboard, Clock, Coins, Lightbulb, Loader2, Play, Sparkles, XCircle } from 'lucide-react';
import { useEffect, useMemo, 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 { Input, Select, Textarea } from '@/components/ui/input';
import { Field } from '@/components/ui/label';
import AppLayout from '@/layouts/AppLayout';
import { dateTime } from '@/lib/format';
import { cn } from '@/lib/utils';

type Settings = {
    enabled: boolean; feedback_ai: boolean; frequency: string; time: string; weekday: number; month_day: number; cron: string; model: string;
    input_price_per_1k: number; output_price_per_1k: number; search_price: number; max_searches: number; tokens_per_search: number; max_output_tokens: number;
    focus: string; next_run_at: string | null; last_run_at: string | null;
};
type Finding = {
    id: string; category: string; severity: string; title: string; detail: string; suggestion: string; diff: string | null; effort: string | null; sources: string[];
    review: { status: 'pending' | 'approved' | 'dismissed'; by: string | null; at: string | null };
};
type Log = {
    log_id: string; execution_time: string; frequency_type: string; status: string; model: string | null; prompt_tokens: number; completion_tokens: number; web_searches: number;
    estimated_cost_usd: number | null; total_cost_usd: number; findings_summary: { summary?: string; findings?: Finding[]; citations?: { url: string; title: string | null }[] } | null;
    error: string | null; duration_ms: number | null;
};
type Feedback = {
    id: number; type: 'bug' | 'suggestion'; message: string; page_url: string | null; status: string; adjustment_approved: boolean; cost_usd: number; ai_error: string | null;
    by: string | null; company: string | null; at: string; processed: boolean; images?: { name: string; size: number; url: string }[];
    structured: { title?: string; category?: string; severity?: string; summary?: string; steps?: string[]; expected?: string; actual?: string; suggested_fix?: string; prompt_adjustment?: string } | null;
};
type Props = {
    settings: Settings; frequencies: Record<string, string>; cron: string; promptTokens: number;
    estimate: { input_tokens: number; output_tokens: number; total_tokens: number; searches: number; cost_usd: number; label: string };
    actualAverage: { tokens: number; cost_usd: number; runs: number } | null; configured: boolean; logs: Log[]; totals: { month_cost_usd: number };
    feedback: Feedback[]; feedbackFilter: 'open' | 'all'; feedbackStatuses: Record<string, string>;
};

const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const usd = (n: number, dp = 2) => `$${n.toFixed(dp)} USD`;
const num = (n: number) => new Intl.NumberFormat('en-AU').format(Math.round(n));
const SEV: Record<string, string> = { critical: 'bg-red-100 text-red-800', high: 'bg-orange-100 text-orange-900', medium: 'bg-amber-100 text-amber-900', low: 'bg-stone-100 text-ink-muted' };
const STATUS: Record<string, string> = { Success: 'bg-green-100 text-green-800', 'No Updates Found': 'bg-stone-100 text-ink', Failed: 'bg-red-100 text-red-800', Running: 'bg-amber-100 text-amber-900' };

/** Same formula as App\Services\Ai\AiSettings::estimate, recalculated live as the settings change. */
function estimateFor(s: Settings, promptTokens: number) {
    const searches = Math.max(0, Number(s.max_searches) || 0);
    const input = promptTokens + searches * Math.max(0, Number(s.tokens_per_search) || 0);
    const output = Math.round(Math.max(500, Number(s.max_output_tokens) || 0) * 0.6);
    const tokenCost = (input / 1000) * (Number(s.input_price_per_1k) || 0) + (output / 1000) * (Number(s.output_price_per_1k) || 0);
    const searchCost = searches * (Number(s.search_price) || 0);
    return { input, output, total: input + output, searches, tokenCost, searchCost, cost: tokenCost + searchCost };
}

export default function AiImprovements(props: Props) {
    const { logs } = props;
    // While an audit runs, refresh the log every 10 seconds.
    const running = logs.some((l) => l.status === 'Running');
    useEffect(() => { if (!running) return; const t = window.setInterval(() => router.reload({ only: ['logs', 'totals', 'actualAverage'] }), 10000); return () => window.clearInterval(t); }, [running]);

    return (
        <AppLayout title="AI improvements">
            <PageHeader title="AI improvements" breadcrumbs={[{ label: 'Settings', href: '/settings/company' }, { label: 'AI improvements' }]}
                description="Staff feedback and scheduled technology audits, powered by Claude. Audits only propose changes: nothing is changed on the live app until it's reviewed and deployed." />
            <SettingsNav />
            {!props.configured && (
                <p className="mb-6 flex max-w-5xl gap-2 rounded-md border border-amber-300 bg-amber-50 px-3 py-2.5 text-sm text-amber-900" data-testid="ai-not-configured">
                    <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" /> Add <code>ANTHROPIC_API_KEY</code> (from console.anthropic.com) to the server’s .env to turn these on. Feedback is still collected without it.
                </p>
            )}
            <div className="grid max-w-5xl gap-6">
                <AuditSettings {...props} />
                <AuditLog logs={logs} month={props.totals.month_cost_usd} />
                <FeedbackInbox items={props.feedback} filter={props.feedbackFilter} statuses={props.feedbackStatuses} />
            </div>
        </AppLayout>
    );
}

function AuditSettings({ settings, frequencies, promptTokens, actualAverage, configured }: Props) {
    const form = useForm<Settings>({ ...settings });
    const d = form.data;
    const est = useMemo(() => estimateFor(d, promptTokens), [d, promptTokens]);
    const save = (e: React.FormEvent) => { e.preventDefault(); form.put('/settings/ai', { preserveScroll: true }); };
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const set = <K extends keyof Settings>(k: K, v: Settings[K]) => form.setData(k, v as any);

    return (
        <Card data-testid="ai-settings">
            <CardHeader title="Tech evolution audits" description="On a schedule, Claude checks our packages, integrations and templates against current releases and security advisories (with web search), and proposes updates for review."
                actions={<Badge className={settings.enabled ? 'bg-green-100 text-green-800' : 'bg-stone-100 text-ink-muted'}>{settings.enabled ? 'On' : 'Off'}</Badge>} />
            <CardBody>
                <form onSubmit={save} className="space-y-5">
                    <div className="flex flex-wrap items-center justify-between gap-3 rounded-md border border-line px-4 py-3">
                        <Checkbox label={<span className="font-medium">Run background tech audits</span>} checked={d.enabled} onChange={(e) => set('enabled', e.target.checked)} data-testid="ai-enabled" />
                        <span className="text-xs text-ink-muted">{settings.enabled && settings.next_run_at ? <>Next run: <b className="text-ink">{dateTime(settings.next_run_at)}</b></> : 'Switched off: no background checks run.'}</span>
                    </div>

                    <div className="grid gap-4 sm:grid-cols-4">
                        <Field label="How often" htmlFor="ai-frequency">
                            <Select id="ai-frequency" value={d.frequency} onChange={(e) => set('frequency', e.target.value)} data-testid="ai-frequency">
                                {Object.entries(frequencies).map(([k, v]) => <option key={k} value={k}>{v}</option>)}
                            </Select>
                        </Field>
                        {d.frequency !== 'custom' && (
                            <Field label="Time (Sydney)" htmlFor="ai-time" error={form.errors.time}>
                                <Input id="ai-time" type="time" value={d.time} onChange={(e) => set('time', e.target.value)} />
                            </Field>
                        )}
                        {(d.frequency === 'weekly' || d.frequency === 'biweekly') && (
                            <Field label="Day" htmlFor="ai-weekday">
                                <Select id="ai-weekday" value={d.weekday} onChange={(e) => set('weekday', Number(e.target.value))}>{DAYS.map((n, i) => <option key={n} value={i}>{n}</option>)}</Select>
                            </Field>
                        )}
                        {d.frequency === 'monthly' && (
                            <Field label="Day of month" htmlFor="ai-mday">
                                <Select id="ai-mday" value={d.month_day} onChange={(e) => set('month_day', Number(e.target.value))}>{Array.from({ length: 28 }, (_, i) => <option key={i} value={i + 1}>{i + 1}</option>)}</Select>
                            </Field>
                        )}
                        {d.frequency === 'custom' && (
                            <Field label="Cron schedule (Sydney time)" htmlFor="ai-cron" error={form.errors.cron} hint="minute hour day month weekday, e.g. 0 3 * * 1 = 3 am Mondays" className="sm:col-span-3">
                                <Input id="ai-cron" value={d.cron} onChange={(e) => set('cron', e.target.value)} placeholder="0 3 * * 1" data-testid="ai-cron" />
                            </Field>
                        )}
                    </div>

                    {/* Pre-flight estimate: updates live with the settings. */}
                    <div className="rounded-md border border-line bg-stone-50 px-4 py-3" data-testid="ai-estimate">
                        <div className="flex flex-wrap items-center gap-2 text-sm">
                            <Coins className="h-4 w-4 text-ink-muted" aria-hidden />
                            <b>Estimated Run: ~{num(est.total)} tokens / ${est.cost.toFixed(2)} USD</b>
                            {actualAverage && <span className="text-xs text-ink-muted">· last {actualAverage.runs} runs averaged ~{num(actualAverage.tokens)} tokens / {usd(actualAverage.cost_usd)}</span>}
                        </div>
                        <p className="mt-1 text-xs text-ink-muted">
                            {num(est.input)} input tokens (prompt ~{num(promptTokens)} + {est.searches} web searches × ~{num(Number(d.tokens_per_search))}) × ${Number(d.input_price_per_1k)}/1K
                            {' '}+ {num(est.output)} output tokens × ${Number(d.output_price_per_1k)}/1K = ${est.tokenCost.toFixed(4)}
                            {' '}+ {est.searches} searches × ${Number(d.search_price)} = ${est.searchCost.toFixed(2)}.
                        </p>
                    </div>

                    <details className="rounded-md border border-line px-4 py-3">
                        <summary className="cursor-pointer text-sm font-medium">What to audit, model and pricing</summary>
                        <div className="mt-4 space-y-4">
                            <Field label="Focus areas (one per line)" htmlFor="ai-focus" hint="Staff feedback you approve below is added to these instructions automatically.">
                                <Textarea id="ai-focus" rows={6} value={d.focus} onChange={(e) => set('focus', e.target.value)} />
                            </Field>
                            <div className="grid gap-4 sm:grid-cols-3">
                                <Field label="Claude model" htmlFor="ai-model" error={form.errors.model}><Input id="ai-model" value={d.model} onChange={(e) => set('model', e.target.value.trim())} /></Field>
                                <Field label="Input price (USD per 1K tokens)" htmlFor="ai-in"><Input id="ai-in" type="number" step="0.0001" min="0" value={d.input_price_per_1k} onChange={(e) => set('input_price_per_1k', Number(e.target.value))} /></Field>
                                <Field label="Output price (USD per 1K tokens)" htmlFor="ai-out"><Input id="ai-out" type="number" step="0.0001" min="0" value={d.output_price_per_1k} onChange={(e) => set('output_price_per_1k', Number(e.target.value))} /></Field>
                                <Field label="Web searches per run (max)" htmlFor="ai-searches"><Input id="ai-searches" type="number" min="0" max="20" value={d.max_searches} onChange={(e) => set('max_searches', Number(e.target.value))} data-testid="ai-searches" /></Field>
                                <Field label="Price per web search (USD)" htmlFor="ai-sp"><Input id="ai-sp" type="number" step="0.001" min="0" value={d.search_price} onChange={(e) => set('search_price', Number(e.target.value))} /></Field>
                                <Field label="Tokens per search result (estimate)" htmlFor="ai-tps"><Input id="ai-tps" type="number" min="500" value={d.tokens_per_search} onChange={(e) => set('tokens_per_search', Number(e.target.value))} /></Field>
                                <Field label="Max output tokens" htmlFor="ai-maxout"><Input id="ai-maxout" type="number" min="1000" max="32000" value={d.max_output_tokens} onChange={(e) => set('max_output_tokens', Number(e.target.value))} /></Field>
                            </div>
                            <p className="text-xs text-ink-muted">Defaults are Claude Sonnet 5.5 list prices ($2 / $10 per million tokens) and $10 per 1,000 web searches. Check anthropic.com/pricing if they change.</p>
                        </div>
                    </details>

                    <Checkbox label="Use Claude to turn staff feedback into structured tickets" checked={d.feedback_ai} onChange={(e) => set('feedback_ai', e.target.checked)} />

                    <div className="flex flex-wrap justify-end gap-2">
                        <Button type="button" variant="secondary" disabled={!configured} onClick={() => router.post('/settings/ai/run', {}, { preserveScroll: true })} data-testid="ai-run-now"><Play className="h-4 w-4" /> Run audit now</Button>
                        <Button type="submit" disabled={form.processing} data-testid="ai-save">{form.processing && <Loader2 className="h-4 w-4 animate-spin" />} Save</Button>
                    </div>
                </form>
            </CardBody>
        </Card>
    );
}

function AuditLog({ logs, month }: { logs: Log[]; month: number }) {
    const [open, setOpen] = useState<string | null>(logs[0]?.log_id ?? null);
    return (
        <Card data-testid="ai-log">
            <CardHeader title="Tech audit & cost log" description={`Every audit with its tokens and cost. AI spend this month (audits + feedback): ${usd(month)}.`} />
            <CardBody className="p-0">
                {logs.length === 0 ? <p className="px-5 py-6 text-sm text-ink-muted">No audits 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">When</th><th className="px-3 py-2 font-medium">Status</th><th className="px-3 py-2 text-right font-medium">Prompt / completion tokens</th><th className="px-3 py-2 text-right font-medium">Cost</th><th className="px-5 py-2 font-medium">Findings</th></tr>
                        </thead>
                        <tbody>
                            {logs.map((l) => {
                                const f = l.findings_summary?.findings ?? [];
                                const isOpen = open === l.log_id;
                                return [
                                    <tr key={l.log_id} className="cursor-pointer border-t border-line hover:bg-stone-50" onClick={() => setOpen(isOpen ? null : l.log_id)} data-testid={`ai-log-${l.log_id}`}>
                                        <td className="px-5 py-2.5"><span className="inline-flex items-center gap-1.5">{isOpen ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronRight className="h-3.5 w-3.5" />}{dateTime(l.execution_time)}</span><div className="pl-5 text-xs text-ink-muted">{l.frequency_type}{l.model ? ` · ${l.model}` : ''}</div></td>
                                        <td className="px-3 py-2.5"><Badge className={STATUS[l.status] ?? 'bg-stone-100'}>{l.status === 'Running' && <Loader2 className="mr-1 h-3 w-3 animate-spin" />}{l.status}</Badge></td>
                                        <td className="px-3 py-2.5 text-right tabular-nums">{num(l.prompt_tokens)} / {num(l.completion_tokens)}{l.web_searches ? <div className="text-xs text-ink-muted">{l.web_searches} searches</div> : null}</td>
                                        <td className="px-3 py-2.5 text-right tabular-nums">${l.total_cost_usd.toFixed(4)}{l.estimated_cost_usd !== null && <div className="text-xs text-ink-muted">est. ${l.estimated_cost_usd.toFixed(2)}</div>}</td>
                                        <td className="px-5 py-2.5 text-xs">{l.status === 'Failed' ? <span className="text-red-700">{l.error}</span> : `${f.length} proposed${f.filter((x) => x.review.status === 'approved').length ? ` · ${f.filter((x) => x.review.status === 'approved').length} approved` : ''}`}</td>
                                    </tr>,
                                    isOpen && (
                                        <tr key={`${l.log_id}-d`} className="border-t border-line bg-stone-50/60">
                                            <td colSpan={5} className="px-5 py-4"><Findings log={l} /></td>
                                        </tr>
                                    ),
                                ];
                            })}
                        </tbody>
                    </table>
                )}
            </CardBody>
        </Card>
    );
}

function Findings({ log }: { log: Log }) {
    const s = log.findings_summary;
    const findings = s?.findings ?? [];
    const [copied, setCopied] = useState(false);
    const review = (id: string, status: Finding['review']['status']) => router.put(`/settings/ai/logs/${log.log_id}/findings/${id}`, { status }, { preserveScroll: true, preserveState: true });
    const approved = findings.filter((f) => f.review.status === 'approved');
    const brief = () => approved.map((f, i) => `${i + 1}. [${f.severity}] ${f.title}\n${f.detail}\nSuggestion: ${f.suggestion}${f.diff ? `\n\n${f.diff}` : ''}${f.sources.length ? `\nSources: ${f.sources.join(', ')}` : ''}`).join('\n\n');
    if (log.status === 'Running') return <p className="flex items-center gap-2 text-sm text-ink-muted"><Loader2 className="h-4 w-4 animate-spin" /> Auditing… this usually takes a few minutes.</p>;
    if (log.status === 'Failed') return <p className="text-sm text-red-700">{log.error}</p>;
    return (
        <div className="space-y-3">
            {s?.summary && <p className="text-sm">{s.summary}</p>}
            {findings.length === 0 && <p className="text-sm text-ink-muted">No updates found.</p>}
            {findings.map((f) => (
                <div key={f.id} className={cn('rounded-md border bg-surface px-4 py-3', f.review.status === 'dismissed' ? 'border-line opacity-60' : 'border-line')} data-testid="ai-finding">
                    <div className="flex flex-wrap items-center gap-2">
                        <Badge className={SEV[f.severity] ?? SEV.low}>{f.severity}</Badge>
                        <span className="text-xs uppercase tracking-wide text-ink-muted">{f.category}{f.effort ? ` · ${f.effort} effort` : ''}</span>
                        <b className="min-w-0 flex-1 text-sm">{f.title}</b>
                        {f.review.status === 'pending' ? (
                            <span className="flex gap-1.5">
                                <Button type="button" size="sm" variant="secondary" onClick={() => review(f.id, 'approved')} data-testid="finding-approve"><CheckCircle2 className="h-3.5 w-3.5" /> Approve</Button>
                                <Button type="button" size="sm" variant="ghost" onClick={() => review(f.id, 'dismissed')}><XCircle className="h-3.5 w-3.5" /> Dismiss</Button>
                            </span>
                        ) : (
                            <span className="text-xs text-ink-muted">{f.review.status === 'approved' ? 'Approved' : 'Dismissed'}{f.review.by ? ` by ${f.review.by}` : ''} · <button type="button" className="underline" onClick={() => review(f.id, 'pending')}>undo</button></span>
                        )}
                    </div>
                    {f.detail && <p className="mt-2 text-sm">{f.detail}</p>}
                    {f.suggestion && <p className="mt-1.5 text-sm"><b>Suggestion:</b> {f.suggestion}</p>}
                    {f.diff && <pre className="mt-2 max-h-72 overflow-auto rounded bg-stone-900 p-3 text-xs text-stone-100">{f.diff}</pre>}
                    {f.sources.length > 0 && <p className="mt-2 flex flex-wrap gap-x-3 gap-y-1 text-xs">{f.sources.map((u) => <a key={u} href={u} target="_blank" rel="noreferrer" className="text-link underline">{new URL(u).hostname}</a>)}</p>}
                </div>
            ))}
            {approved.length > 0 && (
                <div className="flex flex-wrap items-center gap-3 rounded-md border border-line bg-surface px-4 py-2.5 text-sm">
                    <span className="min-w-0 flex-1">{approved.length} approved. Approved items are queued for development: nothing changes on the live app until they're built and deployed.</span>
                    <Button type="button" size="sm" variant="secondary" onClick={() => { void navigator.clipboard?.writeText(brief()); setCopied(true); window.setTimeout(() => setCopied(false), 1500); }}>
                        <Clipboard className="h-3.5 w-3.5" /> {copied ? 'Copied' : 'Copy developer brief'}
                    </Button>
                </div>
            )}
        </div>
    );
}

function FeedbackInbox({ items, filter, statuses }: { items: Feedback[]; filter: 'open' | 'all'; statuses: Record<string, string> }) {
    const update = (id: number, data: Record<string, string | boolean>) => router.put(`/settings/ai/feedback/${id}`, data, { preserveScroll: true, preserveState: true });
    return (
        <Card data-testid="ai-feedback">
            <CardHeader title="Feedback inbox" description="Bug reports and suggestions from the Feedback button, structured by Claude. Approve a prompt adjustment to have future tech audits follow it."
                actions={
                    <div className="inline-flex rounded-md border border-line p-0.5 text-xs">
                        {(['open', 'all'] as const).map((f) => (
                            <button key={f} type="button" aria-pressed={filter === f} onClick={() => router.get('/settings/ai', f === 'all' ? { feedback: 'all' } : {}, { 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 === 'open' ? 'Open' : 'All'}</button>
                        ))}
                    </div>
                } />
            <CardBody className="space-y-3">
                {items.length === 0 && <p className="text-sm text-ink-muted">No feedback yet. Staff can send it from the Feedback button in the top bar.</p>}
                {items.map((f) => {
                    const s = f.structured;
                    return (
                        <div key={f.id} className="rounded-md border border-line px-4 py-3" data-testid="feedback-item">
                            <div className="flex flex-wrap items-center gap-2">
                                {f.type === 'bug' ? <Bug className="h-4 w-4 text-red-700" aria-label="Bug" /> : <Lightbulb className="h-4 w-4 text-amber-600" aria-label="Suggestion" />}
                                <b className="min-w-0 flex-1 text-sm">{s?.title ?? f.message.slice(0, 90)}</b>
                                {s?.severity && <Badge className={SEV[s.severity] ?? SEV.low}>{s.severity}</Badge>}
                                <Select aria-label="Status" className="h-8 w-auto text-xs" value={f.status} onChange={(e) => update(f.id, { status: e.target.value })}>
                                    {Object.entries(statuses).map(([k, v]) => <option key={k} value={k}>{v}</option>)}
                                </Select>
                            </div>
                            <p className="mt-1 text-xs text-ink-muted"><Clock className="mr-1 inline h-3 w-3" />{dateTime(f.at)}{f.by ? ` · ${f.by}` : ''}{f.company ? ` (${f.company})` : ''}{f.page_url ? ` · ${f.page_url}` : ''}</p>
                            {f.images && f.images.length > 0 && (
                                <div className="mt-2 flex flex-wrap gap-2" data-testid="feedback-item-images">
                                    {f.images.map((im) => (
                                        <a key={im.url} href={im.url} target="_blank" rel="noreferrer" className="block h-20 w-28 overflow-hidden rounded-md border border-line bg-stone-50 hover:ring-2 hover:ring-accent" title={im.name}>
                                            <img src={im.url} alt={im.name} className="h-full w-full object-cover" loading="lazy" />
                                        </a>
                                    ))}
                                </div>
                            )}
                            {s ? (
                                <div className="mt-2 space-y-1.5 text-sm">
                                    {s.summary && <p>{s.summary}</p>}
                                    {s.steps && s.steps.length > 0 && <ol className="list-decimal pl-5 text-ink-muted">{s.steps.map((x, i) => <li key={i}>{x}</li>)}</ol>}
                                    {(s.expected || s.actual) && <p className="text-ink-muted">{s.expected && <>Expected: {s.expected}. </>}{s.actual && <>Actual: {s.actual}.</>}</p>}
                                    {s.suggested_fix && <p><b>Suggested fix:</b> {s.suggested_fix}</p>}
                                    {s.prompt_adjustment && (
                                        <div className="flex flex-wrap items-center gap-3 rounded-md bg-stone-50 px-3 py-2">
                                            <Sparkles className="h-4 w-4 text-ink-muted" aria-hidden />
                                            <span className="min-w-0 flex-1 text-xs"><b>Audit guidance:</b> {s.prompt_adjustment}</span>
                                            <Checkbox label={<span className="text-xs">Use in tech audits</span>} checked={f.adjustment_approved} onChange={(e) => update(f.id, { adjustment_approved: e.target.checked })} />
                                        </div>
                                    )}
                                    <details className="text-xs text-ink-muted"><summary className="cursor-pointer">Original message</summary><p className="mt-1 whitespace-pre-wrap">{f.message}</p></details>
                                </div>
                            ) : (
                                <div className="mt-2 text-sm">
                                    <p className="whitespace-pre-wrap">{f.message}</p>
                                    {f.ai_error ? <p className="mt-1 text-xs text-red-700">Couldn’t structure it: {f.ai_error} <button type="button" className="underline" onClick={() => update(f.id, { retry: true })}>Try again</button></p>
                                        : !f.processed && <p className="mt-1 text-xs text-ink-muted">Not structured yet{f.cost_usd === 0 ? ' (needs the Claude API key)' : ''}.</p>}
                                </div>
                            )}
                        </div>
                    );
                })}
            </CardBody>
        </Card>
    );
}
