'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * Per-form submissions (entries) — a compact, token-only table wired to the
 * real entries API (`lib/forms-service.ts`). Replaces the previous card list.
 *
 * Features: summary chips, search + status pills (All / Unread / Starred /
 * Archived), row selection with bulk actions (mark read, star, archive,
 * delete), per-row star toggle, CSV export, and a detail drawer that opens on
 * row click (marking the entry read). Loading / empty / filtered-empty / error
 * states are all handled.
 */
import { useCallback, useEffect, useState } from 'react';
import { ArrowLeft, Download, Inbox, Search } from 'lucide-react';
import { toast } from 'sonner';
import { bulkUpdateEntries, deleteEntry, fetchEntries, fetchEntryCounts, fetchFormById, updateEntry, } from '../lib/forms-service.js';
import { emitFormsChanged, onFormsChanged } from '../lib/forms-events.js';
import { EntryDetailDrawer } from '../components/forms/EntryDetailDrawer.js';
import { EntriesTable } from '../components/forms/EntriesTable.js';
import { ConfirmDialog } from '../components/ui/ConfirmDialog.js';
import { FormsEmptyState, FormsErrorState, FormsLoading, FormsPagination, SummaryChip, btnSecondary, } from '../components/forms/primitives.js';
const FILTERS = [
    { id: 'all', label: 'All' },
    { id: 'unread', label: 'Unread' },
    { id: 'starred', label: 'Starred' },
    { id: 'archived', label: 'Archived' },
];
const PAGE_SIZE = 25;
function filterToParams(filter) {
    switch (filter) {
        case 'unread':
            return { unread: true };
        case 'starred':
            return { starred: true };
        case 'archived':
            return { archived: true };
        default:
            return {};
    }
}
function csvEscape(value) {
    const s = value == null ? '' : typeof value === 'object' ? JSON.stringify(value) : String(value);
    return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}
function exportCsv(entries, formSlug) {
    const dataKeys = [...new Set(entries.flatMap((e) => Object.keys(e.data ?? {})))];
    const header = ['Entry', 'Submitted', 'Name', 'Email', 'Phone', 'Status', ...dataKeys];
    const lines = [header.map(csvEscape).join(',')];
    for (const e of entries) {
        const row = [
            e.entryNumber ?? '',
            e.submittedAt,
            e.senderName ?? '',
            e.senderEmail ?? '',
            e.senderPhone ?? '',
            e.unread ? 'unread' : 'read',
            ...dataKeys.map((k) => e.data?.[k]),
        ];
        lines.push(row.map(csvEscape).join(','));
    }
    const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${formSlug || 'form'}-submissions.csv`;
    a.click();
    URL.revokeObjectURL(url);
}
export function FormSubmissions({ formId, onNavigate }) {
    const [formName, setFormName] = useState('');
    const [formSlug, setFormSlug] = useState('');
    const [entries, setEntries] = useState([]);
    const [total, setTotal] = useState(0);
    const [counts, setCounts] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [search, setSearch] = useState('');
    const [filter, setFilter] = useState('all');
    const [page, setPage] = useState(1);
    const [selected, setSelected] = useState(new Set());
    const [activeEntry, setActiveEntry] = useState(null);
    const [drawerOpen, setDrawerOpen] = useState(false);
    const [confirmBulkDelete, setConfirmBulkDelete] = useState(false);
    // Form metadata for the title (loads once).
    useEffect(() => {
        let cancelled = false;
        void fetchFormById(formId)
            .then((form) => {
            if (cancelled || !form)
                return;
            setFormName(form.name);
            setFormSlug(form.slug);
        })
            .catch(() => { });
        return () => {
            cancelled = true;
        };
    }, [formId]);
    const loadCounts = useCallback(() => {
        void fetchEntryCounts({ formId })
            .then(setCounts)
            .catch(() => { });
    }, [formId]);
    const load = useCallback(async () => {
        setLoading(true);
        setError(null);
        try {
            const result = await fetchEntries({
                formId,
                search: search.trim() || undefined,
                page,
                pageSize: PAGE_SIZE,
                ...filterToParams(filter),
            });
            setEntries(result.entries);
            setTotal(result.total);
            setSelected(new Set());
        }
        catch (e) {
            setError(e instanceof Error ? e.message : 'Failed to load submissions');
        }
        finally {
            setLoading(false);
        }
    }, [formId, search, filter, page]);
    useEffect(() => {
        void load();
    }, [load]);
    useEffect(() => {
        loadCounts();
    }, [loadCounts]);
    // Refresh when another surface (drawer, sidebar) signals a change.
    useEffect(() => onFormsChanged(() => {
        loadCounts();
    }), [loadCounts]);
    const refresh = useCallback(() => {
        void load();
        loadCounts();
    }, [load, loadCounts]);
    const openEntry = useCallback((id) => {
        setActiveEntry(id);
        setDrawerOpen(true);
        // Reflect read state immediately in the row; the drawer persists it.
        setEntries((cur) => cur.map((e) => (e.id === id ? { ...e, unread: false } : e)));
    }, []);
    const toggleStar = useCallback(async (entry) => {
        const next = !entry.starred;
        setEntries((cur) => cur.map((e) => (e.id === entry.id ? { ...e, starred: next } : e)));
        const res = await updateEntry(entry.id, { starred: next });
        if (res.error) {
            setEntries((cur) => cur.map((e) => (e.id === entry.id ? { ...e, starred: !next } : e)));
            toast.error(res.error);
            return;
        }
        emitFormsChanged();
    }, []);
    const allSelected = entries.length > 0 && selected.size === entries.length;
    const toggleSelectAll = useCallback(() => {
        setSelected((cur) => cur.size === entries.length ? new Set() : new Set(entries.map((e) => e.id)));
    }, [entries]);
    const toggleSelect = useCallback((id) => {
        setSelected((cur) => {
            const next = new Set(cur);
            if (next.has(id))
                next.delete(id);
            else
                next.add(id);
            return next;
        });
    }, []);
    const bulkPatch = useCallback(async (patch, label) => {
        const ids = [...selected];
        if (ids.length === 0)
            return;
        const res = await bulkUpdateEntries(ids, patch);
        if (res.error) {
            toast.error(res.error);
            return;
        }
        toast.success(`${ids.length} ${ids.length === 1 ? 'entry' : 'entries'} ${label}`);
        emitFormsChanged();
        refresh();
    }, [selected, refresh]);
    const handleBulkDelete = useCallback(async () => {
        const ids = [...selected];
        if (ids.length === 0)
            return;
        const results = await Promise.allSettled(ids.map((id) => deleteEntry(id)));
        const failed = results.filter((r) => r.status === 'rejected' || r.value.error).length;
        if (failed > 0)
            toast.error(`${failed} of ${ids.length} could not be deleted`);
        else
            toast.success(`${ids.length} ${ids.length === 1 ? 'entry' : 'entries'} deleted`);
        emitFormsChanged();
        refresh();
    }, [selected, refresh]);
    const showEmpty = !loading && !error && entries.length === 0;
    const isFiltered = filter !== 'all' || search.trim().length > 0;
    return (_jsxs("div", { className: "space-y-5 p-6", children: [_jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => onNavigate?.('/forms'), className: "text-muted-foreground hover:text-foreground mb-3 inline-flex items-center gap-2 text-sm transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4", "aria-hidden": true }), "Back to Forms"] }), _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground text-2xl font-medium", children: formName ? `${formName} — Submissions` : 'Submissions' }), _jsxs("p", { className: "text-muted-foreground mt-1 text-sm", children: [total, " ", total === 1 ? 'submission' : 'submissions'] })] }), _jsxs("button", { type: "button", className: btnSecondary, onClick: () => exportCsv(entries, formSlug), disabled: entries.length === 0, children: [_jsx(Download, { className: "h-4 w-4", "aria-hidden": true }), "Export CSV"] })] })] }), counts && (_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(SummaryChip, { value: counts.total, label: "total" }), _jsx(SummaryChip, { value: counts.unread, label: "unread", tone: counts.unread > 0 ? 'destructive' : 'neutral' }), _jsx(SummaryChip, { value: counts.starred, label: "starred", tone: "warning" }), _jsx(SummaryChip, { value: counts.thisWeek, label: "this week" })] })), _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { className: "relative w-full sm:max-w-xs", children: [_jsx(Search, { className: "text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2", "aria-hidden": true }), _jsx("input", { type: "search", placeholder: "Search submissions\u2026", value: search, onChange: (e) => {
                                    setSearch(e.target.value);
                                    setPage(1);
                                }, "aria-label": "Search submissions", className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-lg border py-2 pr-3 pl-9 text-sm focus-visible:ring-2 focus-visible:outline-none" })] }), _jsx("div", { className: "flex gap-1", role: "group", "aria-label": "Filter submissions", children: FILTERS.map((f) => (_jsx("button", { type: "button", onClick: () => {
                                setFilter(f.id);
                                setPage(1);
                            }, "aria-pressed": filter === f.id, className: `rounded-full px-3 py-1.5 text-sm font-medium transition-colors ${filter === f.id
                                ? 'bg-primary text-primary-foreground'
                                : 'text-muted-foreground hover:bg-accent hover:text-foreground'}`, children: f.label }, f.id))) })] }), selected.size > 0 && (_jsxs("div", { className: "border-border bg-accent/40 flex flex-wrap items-center gap-2 rounded-lg border px-3 py-2 text-sm", role: "region", "aria-label": "Bulk actions", children: [_jsxs("span", { className: "text-foreground font-medium", children: [selected.size, " selected"] }), _jsx("span", { className: "bg-border mx-1 h-4 w-px", "aria-hidden": true }), _jsx("button", { type: "button", className: "text-foreground hover:bg-accent rounded-md px-2 py-1 font-medium transition-colors", onClick: () => void bulkPatch({ unread: false }, 'marked read'), children: "Mark read" }), _jsx("button", { type: "button", className: "text-foreground hover:bg-accent rounded-md px-2 py-1 font-medium transition-colors", onClick: () => void bulkPatch({ starred: true }, 'starred'), children: "Star" }), _jsx("button", { type: "button", className: "text-foreground hover:bg-accent rounded-md px-2 py-1 font-medium transition-colors", onClick: () => void bulkPatch({ archived: filter !== 'archived' }, filter !== 'archived' ? 'archived' : 'unarchived'), children: filter === 'archived' ? 'Unarchive' : 'Archive' }), _jsx("button", { type: "button", className: "text-destructive hover:bg-destructive/10 rounded-md px-2 py-1 font-medium transition-colors", onClick: () => setConfirmBulkDelete(true), children: "Delete" }), _jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground ml-auto rounded-md px-2 py-1 font-medium transition-colors", onClick: () => setSelected(new Set()), children: "Clear" })] })), error ? (_jsx(FormsErrorState, { message: error, onRetry: load })) : loading ? (_jsx(FormsLoading, { label: "Loading submissions\u2026" })) : showEmpty ? (_jsx(FormsEmptyState, { icon: _jsx(Inbox, { className: "h-6 w-6", "aria-hidden": true }), title: isFiltered ? 'No submissions match your filters' : 'No submissions yet', description: isFiltered
                    ? 'Try a different search term or status filter.'
                    : 'Submissions will appear here once your form starts receiving entries.', action: isFiltered ? (_jsx("button", { type: "button", onClick: () => {
                        setSearch('');
                        setFilter('all');
                        setPage(1);
                    }, className: "text-primary text-sm font-medium hover:underline", children: "Clear filters" })) : undefined })) : (_jsx(EntriesTable, { entries: entries, selected: selected, allSelected: allSelected, onToggleSelectAll: toggleSelectAll, onToggleSelect: toggleSelect, onOpen: openEntry, onToggleStar: toggleStar, footer: _jsx(FormsPagination, { page: page, pageSize: PAGE_SIZE, total: total, onPageChange: setPage, noun: "submission", label: "Submissions pagination" }) })), _jsx(EntryDetailDrawer, { entryId: activeEntry, open: drawerOpen, onOpenChange: setDrawerOpen, onChanged: refresh, onDeleted: () => refresh() }), _jsx(ConfirmDialog, { open: confirmBulkDelete, onClose: () => setConfirmBulkDelete(false), onConfirm: () => void handleBulkDelete(), title: `Delete ${selected.size} ${selected.size === 1 ? 'submission' : 'submissions'}?`, description: "This permanently removes the selected submissions and any attached files. This cannot be undone.", confirmLabel: "Delete", destructive: true })] }));
}
//# sourceMappingURL=FormSubmissions.js.map