'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * Form entry detail pane — inline InspectorPane replacement for the old
 * `EntryDetailDrawer` overlay. Shows a single submission rendered against the
 * schema version it was captured with, plus sender, attribution, and
 * per-entry actions (star, archive, mark unread, delete). Opening an unread
 * entry marks it read. Rendered beside the entries table (400px split pane).
 */
import { useCallback, useEffect, useState } from 'react';
import { Archive, ArchiveRestore, Loader2, Mail, Star, Trash2 } from 'lucide-react';
import { toast } from 'sonner';
import { deleteEntry, fetchEntry, updateEntry, } from '../../lib/forms-service.js';
import { emitFormsChanged } from '../../lib/forms-events.js';
import { ConfirmDialog } from '../ui/ConfirmDialog.js';
import { InspectorPaneBody, InspectorPaneFooter, InspectorPaneHeader, InspectorPaneSection, } from '../ui/InspectorPane.js';
import { FormsErrorState } from './primitives.js';
const iconBtn = 'flex h-7 w-7 shrink-0 items-center justify-center rounded-[6px] text-[var(--muted)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--bg)] hover:text-[var(--txt)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:opacity-60';
function formatDateTime(iso) {
    if (!iso)
        return '—';
    const d = new Date(iso);
    if (Number.isNaN(d.getTime()))
        return '—';
    return d.toLocaleString(undefined, {
        month: 'short',
        day: 'numeric',
        year: 'numeric',
        hour: 'numeric',
        minute: '2-digit',
    });
}
/** Render a stored value for display, coping with arrays/objects/booleans. */
function displayValue(value) {
    if (value == null || value === '')
        return '—';
    if (typeof value === 'boolean')
        return value ? 'Yes' : 'No';
    if (Array.isArray(value))
        return value.map((v) => String(v)).join(', ');
    if (typeof value === 'object')
        return JSON.stringify(value);
    return String(value);
}
function attributionRows(entry) {
    return [
        { label: 'Source', value: entry.utmSource },
        { label: 'Medium', value: entry.utmMedium },
        { label: 'Campaign', value: entry.utmCampaign },
        { label: 'Page', value: entry.pageUrl },
        { label: 'Referrer', value: entry.referrer },
    ].filter((r) => r.value);
}
export function FormEntryDetailPane({ entryId, onClose, onChanged, onDeleted, }) {
    const [detail, setDetail] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [busy, setBusy] = useState(false);
    const [confirmDelete, setConfirmDelete] = useState(false);
    const notifyChanged = useCallback(() => {
        emitFormsChanged();
        onChanged?.();
    }, [onChanged]);
    // Load the entry (and its schema) when the pane opens, marking it read.
    useEffect(() => {
        let cancelled = false;
        setLoading(true);
        setError(null);
        setDetail(null);
        void (async () => {
            try {
                const data = await fetchEntry(entryId);
                if (cancelled)
                    return;
                if (!data) {
                    setError('Entry not found');
                    return;
                }
                setDetail(data);
                // Mark read on open (fire-and-forget; refresh the list counts).
                if (data.entry.unread) {
                    const res = await updateEntry(entryId, { unread: false });
                    if (!cancelled && !res.error)
                        notifyChanged();
                }
            }
            catch (e) {
                if (!cancelled)
                    setError(e instanceof Error ? e.message : 'Failed to load entry');
            }
            finally {
                if (!cancelled)
                    setLoading(false);
            }
        })();
        return () => {
            cancelled = true;
        };
    }, [entryId, notifyChanged]);
    const mutate = useCallback(async (patch) => {
        setBusy(true);
        const res = await updateEntry(entryId, patch);
        setBusy(false);
        if (res.error) {
            toast.error(res.error);
            return;
        }
        setDetail((cur) => (cur ? { ...cur, entry: { ...cur.entry, ...patch } } : cur));
        notifyChanged();
    }, [entryId, notifyChanged]);
    const handleDelete = useCallback(async () => {
        setBusy(true);
        const res = await deleteEntry(entryId);
        setBusy(false);
        if (res.error) {
            toast.error(res.error);
            return;
        }
        toast.success('Submission deleted');
        notifyChanged();
        onDeleted?.(entryId);
    }, [entryId, notifyChanged, onDeleted]);
    const entry = detail?.entry;
    const senderName = entry?.senderName || 'Anonymous';
    const attrRows = entry ? attributionRows(entry) : [];
    return (_jsxs(_Fragment, { children: [_jsx(InspectorPaneHeader, { onClose: onClose, closeLabel: "Close entry details", children: _jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-[13.5px] font-semibold text-[var(--txt)]", children: entry ? `Entry${entry.entryNumber ? ` #${entry.entryNumber}` : ''}` : 'Entry' }), entry && (_jsx("div", { className: "mt-0.5 truncate text-[11.5px] text-[var(--muted)]", children: formatDateTime(entry.submittedAt) }))] }), entry && (_jsxs("div", { className: "flex shrink-0 gap-1", children: [_jsx("button", { type: "button", className: iconBtn, "aria-pressed": entry.starred, "aria-label": entry.starred ? 'Unstar entry' : 'Star entry', disabled: busy, onClick: () => void mutate({ starred: !entry.starred }), children: _jsx(Star, { size: 16, "aria-hidden": true, className: entry.starred ? 'fill-[var(--warn)] text-[var(--warn)]' : '' }) }), _jsx("button", { type: "button", className: iconBtn, "aria-pressed": entry.archived, "aria-label": entry.archived ? 'Unarchive entry' : 'Archive entry', disabled: busy, onClick: () => void mutate({ archived: !entry.archived }), children: entry.archived ? (_jsx(ArchiveRestore, { size: 16, "aria-hidden": true })) : (_jsx(Archive, { size: 16, "aria-hidden": true })) })] }))] }) }), _jsx(InspectorPaneBody, { children: loading ? (_jsxs("div", { className: "flex h-40 items-center justify-center", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "h-5 w-5 animate-spin text-[var(--muted)]", "aria-hidden": true }), _jsx("span", { className: "sr-only", children: "Loading entry\u2026" })] })) : error ? (_jsx("div", { className: "px-4 py-3.5", children: _jsx(FormsErrorState, { message: error }) })) : entry ? (_jsxs(_Fragment, { children: [_jsxs(InspectorPaneSection, { title: "Sender", children: [_jsx("div", { className: "text-[12.5px] font-medium text-[var(--txt)]", children: senderName }), entry.senderEmail && (_jsx("a", { href: `mailto:${entry.senderEmail}`, className: "block truncate text-[12px] text-[var(--acc)] hover:underline", children: entry.senderEmail })), entry.senderPhone && (_jsx("div", { className: "text-[12px] text-[var(--sub)]", children: entry.senderPhone }))] }), _jsx(FieldValues, { entry: entry, fields: detail.fields }), attrRows.length > 0 && (_jsx(InspectorPaneSection, { title: "Attribution", children: _jsx("dl", { children: attrRows.map((row) => (_jsxs("div", { className: "flex justify-between gap-4 py-1 text-[12px]", children: [_jsx("dt", { className: "shrink-0 text-[var(--muted)]", children: row.label }), _jsx("dd", { className: "min-w-0 truncate text-right text-[var(--sub)]", children: row.value })] }, row.label))) }) }))] })) : null }), entry && (_jsx(InspectorPaneFooter, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center justify-center gap-1.5 rounded-[7px] border border-[var(--bdr)] px-3 py-2 text-[12.5px] font-medium text-[var(--txt)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--bg)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:opacity-60", disabled: busy, onClick: () => void mutate({ unread: !entry.unread }), children: [_jsx(Mail, { size: 14, "aria-hidden": true }), "Mark ", entry.unread ? 'read' : 'unread'] }), _jsxs("button", { type: "button", className: "flex shrink-0 items-center justify-center gap-1.5 rounded-[7px] border border-[var(--bdr)] px-3 py-2 text-[12.5px] font-medium text-[var(--err)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--err-l)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:opacity-60", disabled: busy, onClick: () => setConfirmDelete(true), children: [_jsx(Trash2, { size: 14, "aria-hidden": true }), "Delete"] })] }) })), _jsx(ConfirmDialog, { open: confirmDelete, onClose: () => setConfirmDelete(false), onConfirm: () => void handleDelete(), title: "Delete submission?", description: "This permanently removes the submission and any attached files. This cannot be undone.", confirmLabel: "Delete", destructive: true })] }));
}
/** Render the captured field values against the entry's schema. */
function FieldValues({ entry, fields }) {
    // Prefer the schema order; fall back to whatever keys exist on the data.
    const inputFields = fields.filter((f) => f.type !== 'divider' && f.type !== 'richtext' && f.type !== 'honeypot');
    const rows = inputFields.length
        ? inputFields.map((f) => ({ key: f.key, label: f.label }))
        : Object.keys(entry.data ?? {}).map((k) => ({ key: k, label: k }));
    return (_jsx(InspectorPaneSection, { title: "Submission", children: rows.length === 0 ? (_jsx("p", { className: "text-[12px] text-[var(--muted)]", children: "No field data captured." })) : (_jsx("dl", { children: rows.map((row) => (_jsxs("div", { className: "mb-2.5 last:mb-0", children: [_jsx("dt", { className: "text-[10.5px] font-semibold tracking-[0.5px] text-[var(--muted)] uppercase", children: row.label }), _jsx("dd", { className: "mt-0.5 text-[12.5px] break-words whitespace-pre-wrap text-[var(--txt)]", children: displayValue(entry.data?.[row.key]) })] }, row.key))) })) }));
}
//# sourceMappingURL=FormEntryDetailPane.js.map