'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Plus, Search, Tag as TagIcon, Trash2, X, } from 'lucide-react';
import { toast } from 'sonner';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { adminPortalContainer } from '../../lib/portal-container.js';
import { applyPagesQuery, bulkChangePageTags, bulkDeletePages, bulkUpdatePages, fetchPagesDataset, groupPages, } from '../../lib/pages-service.js';
import { PostStatusBadge, SeoScoreIndicator } from '../../components/posts/badges.js';
import { PageTagChip, PageTagsCell } from '../../components/pages/tag-badges.js';
import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js';
const PAGE_SIZE = 25;
export function PagesListView({ onNavigate }) {
    const [search, setSearch] = useState('');
    const [debouncedSearch, setDebouncedSearch] = useState('');
    const [status, setStatus] = useState('all');
    const [groupBy, setGroupBy] = useState('none');
    const [selectedTags, setSelectedTags] = useState(new Set());
    const [sortBy, setSortBy] = useState('title');
    const [dir, setDir] = useState('asc');
    const [page, setPage] = useState(1);
    const [selected, setSelected] = useState(new Set());
    const [dataset, setDataset] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [refreshToken, setRefreshToken] = useState(0);
    const [pendingDelete, setPendingDelete] = useState(false);
    const debounceTimer = useRef(null);
    useEffect(() => {
        if (debounceTimer.current)
            clearTimeout(debounceTimer.current);
        debounceTimer.current = setTimeout(() => {
            setDebouncedSearch(search.trim());
            setPage(1);
        }, 250);
        return () => {
            if (debounceTimer.current)
                clearTimeout(debounceTimer.current);
        };
    }, [search]);
    const tagIds = useMemo(() => [...selectedTags], [selectedTags]);
    // Single network read. Search / sort / group / paging are applied in
    // memory below, so changing any of those never re-fetches. The dataset
    // refreshes only on mount and after a mutation (refreshToken bump).
    useEffect(() => {
        let cancelled = false;
        setLoading(true);
        setError(null);
        fetchPagesDataset()
            .then((res) => {
            if (cancelled)
                return;
            setDataset(res);
            setLoading(false);
        })
            .catch((err) => {
            if (cancelled)
                return;
            setError(err instanceof Error ? err.message : 'Failed to load pages');
            setLoading(false);
        });
        return () => {
            cancelled = true;
        };
    }, [refreshToken]);
    // Reset paging/selection when the active filters change shape.
    useEffect(() => {
        setPage(1);
        setSelected(new Set());
    }, [debouncedSearch, status, tagIds, groupBy]);
    const allPages = useMemo(() => dataset?.pages ?? [], [dataset]);
    const tags = useMemo(() => dataset?.tags ?? [], [dataset]);
    const grandTotal = allPages.length;
    const grouped = groupBy !== 'none';
    const filtered = useMemo(() => applyPagesQuery(allPages, {
        status,
        tagIds,
        search: debouncedSearch,
        sortBy,
        sortDirection: dir,
    }), [allPages, status, tagIds, debouncedSearch, sortBy, dir]);
    const total = filtered.length;
    const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
    // Pagination only applies to the flat view; grouped views render every
    // match so the buckets stay complete.
    const pages = useMemo(() => (grouped ? filtered : filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)), [filtered, grouped, page]);
    const tagBySlug = useMemo(() => {
        const m = new Map();
        for (const t of tags)
            m.set(t.slug, t);
        return m;
    }, [tags]);
    const displayGroups = useMemo(() => groupPages(pages, groupBy, tags), [pages, groupBy, tags]);
    const handleSort = useCallback((field) => {
        if (sortBy === field) {
            setDir((d) => (d === 'asc' ? 'desc' : 'asc'));
        }
        else {
            setSortBy(field);
            setDir(field === 'modified' || field === 'seo' ? 'desc' : 'asc');
        }
    }, [sortBy]);
    // `aria-sort` belongs on the column header cell (`<th>`), not the button
    // inside it — assistive tech reads sort state from the header.
    const ariaSortFor = (field) => sortBy === field ? (dir === 'asc' ? 'ascending' : 'descending') : 'none';
    const filtersAreActive = debouncedSearch !== '' || status !== 'all' || selectedTags.size > 0;
    const clearFilters = () => {
        setSearch('');
        setStatus('all');
        setSelectedTags(new Set());
        setPage(1);
    };
    const toggleTag = (slug) => setSelectedTags((s) => {
        const next = new Set(s);
        if (next.has(slug))
            next.delete(slug);
        else
            next.add(slug);
        return next;
    });
    // ─── Selection ─────────────────────────────────────────────────────
    const toggleOne = (id) => setSelected((s) => {
        const next = new Set(s);
        if (next.has(id))
            next.delete(id);
        else
            next.add(id);
        return next;
    });
    const allOnPageSelected = pages.length > 0 && pages.every((p) => selected.has(p.id));
    const toggleAllOnPage = (checked) => setSelected((s) => {
        const next = new Set(s);
        if (checked)
            for (const p of pages)
                next.add(p.id);
        else
            for (const p of pages)
                next.delete(p.id);
        return next;
    });
    const selectedPages = useMemo(() => pages.filter((p) => selected.has(p.id)), [pages, selected]);
    const deletablePages = useMemo(() => selectedPages.filter((p) => !p.isHomepage), [selectedPages]);
    const blockedHomepage = selectedPages.length !== deletablePages.length;
    // ─── Bulk actions ──────────────────────────────────────────────────
    const afterBulk = () => {
        setSelected(new Set());
        setRefreshToken((t) => t + 1);
    };
    // Bulk service calls always resolve a { ok, failed } tally (they never
    // reject), so we promote a *total* failure to a rejection — that's what
    // makes `toast.promise`'s `error` branch reachable. The `await` is
    // wrapped so a rejection can't escape as an unhandled promise, and
    // `afterBulk` always runs to refresh the (possibly partially-changed) set.
    const allFailed = (r) => r.ok === 0 && r.failed > 0;
    const runBulkStatus = async (target) => {
        const ids = selectedPages.map((p) => p.id);
        if (ids.length === 0)
            return;
        const verb = target === 'PUBLISHED' ? 'Publishing' : 'Updating';
        const promise = bulkUpdatePages(ids, { status: target }).then((r) => {
            if (allFailed(r))
                throw new Error('Bulk update failed');
            return r;
        });
        toast.promise(promise, {
            loading: `${verb} ${ids.length} page${ids.length === 1 ? '' : 's'}…`,
            success: (r) => `${r.ok} updated${r.failed ? `, ${r.failed} failed` : ''}`,
            error: 'Bulk update failed',
        });
        try {
            await promise;
        }
        catch {
            /* surfaced via toast.promise */
        }
        afterBulk();
    };
    const runBulkTag = async (slug, mode) => {
        if (selectedPages.length === 0)
            return;
        const promise = bulkChangePageTags(selectedPages.map((p) => ({ id: p.id, tags: p.tags, primaryTagId: p.primaryTagId })), mode === 'add' ? { add: [slug] } : { remove: [slug] }).then((r) => {
            if (allFailed(r))
                throw new Error('Bulk tag change failed');
            return r;
        });
        const tagName = tagBySlug.get(slug)?.name ?? slug;
        toast.promise(promise, {
            loading: `${mode === 'add' ? 'Adding' : 'Removing'} "${tagName}"…`,
            success: (r) => `${r.ok} page${r.ok === 1 ? '' : 's'} updated${r.failed ? `, ${r.failed} failed` : ''}`,
            error: 'Bulk tag change failed',
        });
        try {
            await promise;
        }
        catch {
            /* surfaced via toast.promise */
        }
        afterBulk();
    };
    const runBulkDelete = async () => {
        const ids = deletablePages.map((p) => p.id);
        if (ids.length === 0)
            return;
        const promise = bulkDeletePages(ids).then((r) => {
            if (allFailed(r))
                throw new Error('Bulk delete failed');
            return r;
        });
        toast.promise(promise, {
            loading: `Deleting ${ids.length} page${ids.length === 1 ? '' : 's'}…`,
            success: (r) => `${r.ok} deleted${r.failed ? `, ${r.failed} failed` : ''}`,
            error: 'Bulk delete failed',
        });
        try {
            await promise;
        }
        catch {
            /* surfaced via toast.promise */
        }
        afterBulk();
    };
    // ─── Render ────────────────────────────────────────────────────────
    return (_jsxs("div", { className: "flex h-full flex-col gap-4 p-4 sm:p-6", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-foreground text-xl font-medium tracking-tight sm:text-2xl", children: "Pages" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [grandTotal, " page", grandTotal === 1 ? '' : 's', " \u00B7 organized by tags"] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("div", { className: "relative max-w-sm flex-1", 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", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search pages", placeholder: "Search pages\u2026", className: "border-border bg-card text-foreground placeholder:text-muted-foreground focus:border-primary focus:ring-primary/30 w-full rounded-lg border py-2 pr-3 pl-9 text-sm shadow-sm focus:ring-2 focus:outline-none" })] }), _jsx(FilterSelect, { label: "Group by", value: groupBy, onChange: (v) => setGroupBy(v), options: [
                            { value: 'none', label: 'None' },
                            { value: 'tag', label: 'Tag' },
                            { value: 'status', label: 'Status' },
                            { value: 'author', label: 'Author' },
                        ] }), _jsx(FilterSelect, { label: "Status", value: status, onChange: (v) => {
                            setStatus(v);
                            setPage(1);
                        }, options: [
                            { value: 'all', label: 'All statuses' },
                            { value: 'PUBLISHED', label: 'Published' },
                            { value: 'DRAFT', label: 'Draft' },
                            { value: 'SCHEDULED', label: 'Scheduled' },
                        ] }), _jsxs("span", { className: "text-muted-foreground ml-auto text-sm tabular-nums", children: [total, " of ", grandTotal] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-muted-foreground text-[10px] font-medium tracking-wider uppercase", children: "Tags" }), tags.map((t) => (_jsx(PageTagChip, { name: t.name, color: t.color, count: t.pageCount, selected: selectedTags.has(t.slug), onToggle: () => toggleTag(t.slug) }, t.slug))), selectedTags.size > 0 && (_jsxs("button", { type: "button", onClick: () => setSelectedTags(new Set()), className: "text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs", children: [_jsx(X, { className: "h-3 w-3", "aria-hidden": true }), "Clear tags"] })), _jsxs("button", { type: "button", onClick: () => onNavigate('/pages/tags'), className: "text-primary ml-auto inline-flex items-center gap-1 text-xs font-medium hover:underline", children: [_jsx(TagIcon, { className: "h-3 w-3", "aria-hidden": true }), "Manage tags"] })] }), selected.size > 0 && (_jsx(BulkActionBar, { count: selected.size, tags: tags, blockedHomepage: blockedHomepage, onClear: () => setSelected(new Set()), onPublish: () => runBulkStatus('PUBLISHED'), onDraft: () => runBulkStatus('DRAFT'), onAddTag: (slug) => runBulkTag(slug, 'add'), onRemoveTag: (slug) => runBulkTag(slug, 'remove'), onDelete: () => setPendingDelete(true), deletableCount: deletablePages.length })), _jsxs("div", { className: "bg-card border-border overflow-hidden rounded-xl border shadow-sm", children: [_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full min-w-[800px] table-fixed", role: "table", "aria-label": "Pages", children: [_jsxs("colgroup", { children: [_jsx("col", { style: { width: '40px' } }), _jsx("col", {}), _jsx("col", { style: { width: '200px' } }), _jsx("col", { style: { width: '170px' } }), _jsx("col", { style: { width: '120px' } }), _jsx("col", { style: { width: '130px' } }), _jsx("col", { style: { width: '80px' } })] }), _jsx("thead", { className: "border-border bg-muted/40 border-b", children: _jsxs("tr", { className: "text-muted-foreground text-xs", children: [_jsx("th", { scope: "col", className: "px-3 py-2.5 text-left", children: _jsx("input", { type: "checkbox", "aria-label": "Select all pages on this page", checked: allOnPageSelected, onChange: (e) => toggleAllOnPage(e.target.checked), className: "border-border accent-primary rounded" }) }), _jsx("th", { scope: "col", "aria-sort": ariaSortFor('title'), className: "px-3 py-2.5 text-left", children: _jsx(SortHeader, { label: "Title", field: "title", current: sortBy, dir: dir, onSort: handleSort }) }), _jsx("th", { scope: "col", className: "px-3 py-2.5 text-left", children: _jsx("span", { className: "text-xs font-medium tracking-wider uppercase", children: "Tags" }) }), _jsx("th", { scope: "col", "aria-sort": ariaSortFor('author'), className: "px-3 py-2.5 text-left", children: _jsx(SortHeader, { label: "Author", field: "author", current: sortBy, dir: dir, onSort: handleSort }) }), _jsx("th", { scope: "col", "aria-sort": ariaSortFor('status'), className: "px-3 py-2.5 text-left", children: _jsx(SortHeader, { label: "Status", field: "status", current: sortBy, dir: dir, onSort: handleSort }) }), _jsx("th", { scope: "col", "aria-sort": ariaSortFor('modified'), className: "px-3 py-2.5 text-left", children: _jsx(SortHeader, { label: "Last Modified", field: "modified", current: sortBy, dir: dir, onSort: handleSort }) }), _jsx("th", { scope: "col", "aria-sort": ariaSortFor('seo'), className: "px-3 py-2.5 text-left", children: _jsx(SortHeader, { label: "SEO", field: "seo", current: sortBy, dir: dir, onSort: handleSort }) })] }) }), _jsxs("tbody", { children: [loading && pages.length === 0 && _jsx(LoadingRows, {}), !loading && error && (_jsx("tr", { children: _jsxs("td", { colSpan: 7, className: "px-3 py-12 text-center", children: [_jsx("div", { className: "text-foreground mb-2 text-sm font-medium", children: error }), _jsx("button", { onClick: () => setRefreshToken((t) => t + 1), className: "text-primary text-sm hover:underline", children: "Try again" })] }) })), !loading && !error && pages.length === 0 && (_jsx(EmptyRow, { filtersActive: filtersAreActive, onClear: clearFilters, onNewPage: () => onNavigate('/pages/new') })), !loading &&
                                            !error &&
                                            displayGroups.map((group) => (_jsx(GroupBlock, { showHeader: grouped, label: group.label, color: group.color, count: group.pages.length, children: group.pages.map((p) => (_jsx(PageRow, { page: p, selected: selected.has(p.id), resolveTag: (slug) => tagBySlug.get(slug), onSelect: () => toggleOne(p.id), onOpen: () => onNavigate(`/pages/${p.id}/edit`) }, p.id))) }, group.key)))] })] }) }), !grouped && (_jsx(PaginationFooter, { page: page, totalPages: totalPages, total: total, pageSize: PAGE_SIZE, onPage: setPage }))] }), _jsx(ConfirmDialog, { open: pendingDelete, title: `Delete ${deletablePages.length} page${deletablePages.length === 1 ? '' : 's'}?`, description: blockedHomepage
                    ? 'The homepage cannot be deleted and will be skipped. The remaining pages move to trash and can be restored for 30 days.'
                    : 'The selected pages move to trash and can be restored for 30 days.', confirmLabel: "Delete", destructive: true, onClose: () => setPendingDelete(false), onConfirm: () => {
                    void runBulkDelete();
                } })] }));
}
// ─── Sub-components ──────────────────────────────────────────────────
function SortHeader({ label, field, current, dir, onSort, }) {
    const active = current === field;
    return (_jsxs("button", { type: "button", onClick: () => onSort(field), className: `hover:text-foreground inline-flex items-center gap-1 text-xs font-medium tracking-wider uppercase transition-colors ${active ? 'text-foreground' : 'text-muted-foreground'}`, children: [_jsx("span", { children: label }), active &&
                (dir === 'asc' ? (_jsx(ChevronUp, { className: "h-3 w-3", "aria-hidden": true })) : (_jsx(ChevronDown, { className: "h-3 w-3", "aria-hidden": true })))] }));
}
function FilterSelect({ label, value, onChange, options, }) {
    return (_jsxs("label", { className: "text-foreground inline-flex items-center gap-1.5 text-sm", children: [_jsxs("span", { className: "text-muted-foreground", children: [label, ":"] }), _jsx("select", { value: value, onChange: (e) => onChange(e.target.value), className: "border-border bg-card text-foreground focus:border-primary focus:ring-primary/30 rounded-lg border px-2.5 py-1.5 text-sm shadow-sm focus:ring-2 focus:outline-none", children: options.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) })] }));
}
function GroupBlock({ showHeader, label, color, count, children, }) {
    return (_jsxs(_Fragment, { children: [showHeader && (_jsx("tr", { className: "bg-muted/30 border-border border-b", children: _jsx("td", { colSpan: 7, className: "px-3 py-2", children: _jsxs("span", { className: "text-foreground inline-flex items-center gap-2 text-xs font-medium tracking-wider uppercase", children: [color && _jsx("span", { "aria-hidden": true, className: `h-2 w-2 rounded-full ${dotFor(color)}` }), label, _jsx("span", { className: "text-muted-foreground tabular-nums", children: count })] }) }) })), children] }));
}
function dotFor(color) {
    const map = {
        purple: 'bg-brand',
        green: 'bg-success',
        orange: 'bg-warning',
        red: 'bg-destructive',
        blue: 'bg-info',
        pink: 'bg-chart-4',
    };
    return map[color] ?? 'bg-muted-foreground';
}
function BulkActionBar({ count, tags, blockedHomepage, deletableCount, onClear, onPublish, onDraft, onAddTag, onRemoveTag, onDelete, }) {
    return (_jsxs("div", { className: "border-primary/30 bg-primary/5 flex flex-wrap items-center gap-2 rounded-lg border px-4 py-2", children: [_jsxs("span", { className: "text-foreground text-sm font-medium", children: [count, " selected"] }), _jsx("div", { className: "bg-border h-4 w-px", "aria-hidden": true }), _jsx("button", { type: "button", onClick: onPublish, className: "text-foreground hover:bg-accent rounded-md px-2 py-1 text-sm transition-colors", children: "Publish" }), _jsx("button", { type: "button", onClick: onDraft, className: "text-foreground hover:bg-accent rounded-md px-2 py-1 text-sm transition-colors", children: "Move to draft" }), _jsx(TagMenu, { label: "Add tag", tags: tags, onPick: onAddTag }), _jsx(TagMenu, { label: "Remove tag", tags: tags, onPick: onRemoveTag }), _jsxs("button", { type: "button", onClick: onDelete, disabled: deletableCount === 0, title: blockedHomepage ? 'The homepage is excluded from deletion' : undefined, className: "text-destructive hover:bg-destructive/10 inline-flex items-center gap-1 rounded-md px-2 py-1 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-40", children: [_jsx(Trash2, { className: "h-3.5 w-3.5", "aria-hidden": true }), "Delete"] }), _jsxs("button", { type: "button", onClick: onClear, className: "text-muted-foreground hover:text-foreground ml-auto inline-flex items-center gap-1 rounded-md px-2 py-1 text-sm transition-colors", children: [_jsx(X, { className: "h-3.5 w-3.5", "aria-hidden": true }), "Clear"] })] }));
}
function TagMenu({ label, tags, onPick, }) {
    return (_jsxs(DropdownMenu.Root, { children: [_jsx(DropdownMenu.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: "text-foreground hover:bg-accent inline-flex items-center gap-1 rounded-md px-2 py-1 text-sm transition-colors", children: [label, _jsx(ChevronDown, { className: "h-3 w-3", "aria-hidden": true })] }) }), _jsx(DropdownMenu.Portal, { container: adminPortalContainer(), children: _jsx(DropdownMenu.Content, { align: "start", sideOffset: 4, className: "border-border bg-popover z-50 max-h-64 w-44 overflow-auto rounded-lg border p-1 shadow-md", children: tags.length === 0 ? (_jsx("div", { className: "text-muted-foreground px-2 py-1.5 text-xs", children: "No tags yet" })) : (tags.map((t) => (_jsxs(DropdownMenu.Item, { onSelect: () => onPick(t.slug), className: "text-foreground focus:bg-accent flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none", children: [_jsx("span", { "aria-hidden": true, className: `h-2 w-2 rounded-full ${dotFor(t.color ?? 'gray')}` }), t.name] }, t.slug)))) }) })] }));
}
function PageRow({ page, selected, resolveTag, onSelect, onOpen, }) {
    return (_jsxs("tr", { className: `border-border hover:bg-muted/30 group border-b transition-colors last:border-b-0 ${selected ? 'bg-primary/5' : ''}`, children: [_jsx("td", { className: "px-3 py-3", onClick: (e) => e.stopPropagation(), children: _jsx("input", { type: "checkbox", "aria-label": `Select "${page.title}"`, checked: selected, onChange: onSelect, className: "border-border accent-primary rounded" }) }), _jsx("td", { className: "px-3 py-3", children: _jsxs("button", { type: "button", onClick: onOpen, className: "flex w-full items-center gap-3 text-left", children: [_jsx("span", { "aria-hidden": true, className: "bg-muted block h-9 w-9 shrink-0 rounded-md" }), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground group-hover:text-primary block truncate text-sm font-medium", children: page.title }), _jsx("span", { className: "text-muted-foreground block truncate text-xs", children: page.path })] })] }) }), _jsx("td", { className: "px-3 py-3", children: _jsx(PageTagsCell, { tagSlugs: page.tags, primaryTagId: page.primaryTagId, resolve: resolveTag }) }), _jsx("td", { className: "px-3 py-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { "aria-hidden": true, className: "bg-muted text-muted-foreground inline-flex h-7 w-7 items-center justify-center rounded-full text-[11px] font-medium", children: page.authorInitials }), _jsx("span", { className: "text-foreground truncate text-sm", children: page.authorName })] }) }), _jsx("td", { className: "px-3 py-3", children: _jsx(PostStatusBadge, { status: page.status }) }), _jsx("td", { className: "text-muted-foreground px-3 py-3 text-sm tabular-nums", children: formatDateShort(page.lastModified) }), _jsx("td", { className: "px-3 py-3", children: _jsx(SeoScoreIndicator, { score: page.seoScore }) })] }));
}
function LoadingRows() {
    return (_jsx(_Fragment, { children: Array.from({ length: 8 }).map((_, i) => (_jsx("tr", { className: "border-border border-b last:border-b-0", children: Array.from({ length: 7 }).map((__, j) => (_jsx("td", { className: "px-3 py-3", children: _jsx("div", { className: "bg-muted h-4 w-full animate-pulse rounded" }) }, j))) }, i))) }));
}
function EmptyRow({ filtersActive, onClear, onNewPage, }) {
    return (_jsx("tr", { children: _jsxs("td", { colSpan: 7, className: "px-3 py-16 text-center", children: [_jsx("div", { className: "text-foreground mb-2 text-sm font-medium", children: filtersActive ? 'No pages match your filters' : 'No pages yet' }), _jsx("div", { className: "text-muted-foreground mb-4 text-sm", children: filtersActive
                        ? 'Try clearing the search, tags, or status filter above.'
                        : 'Create your first page to get started.' }), filtersActive ? (_jsx("button", { type: "button", onClick: onClear, className: "text-primary text-sm hover:underline", children: "Clear filters" })) : (_jsxs("button", { type: "button", onClick: onNewPage, className: "bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-1.5 rounded-lg px-3.5 py-1.5 text-sm font-medium shadow-sm transition-colors", children: [_jsx(Plus, { className: "h-3.5 w-3.5", "aria-hidden": true }), "New page"] }))] }) }));
}
function PaginationFooter({ page, totalPages, total, pageSize, onPage, }) {
    const start = total === 0 ? 0 : (page - 1) * pageSize + 1;
    const end = Math.min(total, page * pageSize);
    return (_jsxs("div", { className: "border-border flex items-center justify-between border-t px-4 py-3 text-sm", children: [_jsxs("span", { className: "text-muted-foreground tabular-nums", children: [start, "\u2013", end, " of ", total, " page", total === 1 ? '' : 's'] }), _jsxs("nav", { className: "flex items-center gap-1", "aria-label": "Pages pagination", children: [_jsx("button", { type: "button", onClick: () => onPage(Math.max(1, page - 1)), disabled: page === 1, "aria-label": "Previous page", className: "border-border bg-background text-foreground hover:bg-accent inline-flex h-8 w-8 items-center justify-center rounded-md border transition-colors disabled:cursor-not-allowed disabled:opacity-40", children: _jsx(ChevronLeft, { className: "h-4 w-4", "aria-hidden": true }) }), pageNumbers(page, totalPages).map((p, idx) => p === '…' ? (_jsx("span", { "aria-hidden": true, className: "text-muted-foreground inline-flex h-8 w-8 items-center justify-center text-sm", children: "\u2026" }, `gap-${idx}`)) : (_jsx("button", { type: "button", onClick: () => onPage(p), "aria-current": p === page ? 'page' : undefined, className: `inline-flex h-8 w-8 items-center justify-center rounded-md text-sm tabular-nums transition-colors ${p === page
                            ? 'bg-primary text-primary-foreground'
                            : 'border-border bg-background text-foreground hover:bg-accent border'}`, children: p }, p))), _jsx("button", { type: "button", onClick: () => onPage(Math.min(totalPages, page + 1)), disabled: page === totalPages, "aria-label": "Next page", className: "border-border bg-background text-foreground hover:bg-accent inline-flex h-8 w-8 items-center justify-center rounded-md border transition-colors disabled:cursor-not-allowed disabled:opacity-40", children: _jsx(ChevronRight, { className: "h-4 w-4", "aria-hidden": true }) })] })] }));
}
// ─── Helpers ─────────────────────────────────────────────────────────
function formatDateShort(input) {
    const d = new Date(input);
    if (Number.isNaN(d.getTime()))
        return '—';
    return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
}
export function pageNumbers(current, total) {
    if (total <= 7)
        return Array.from({ length: total }, (_, i) => i + 1);
    const out = [1];
    const start = Math.max(2, current - 1);
    const end = Math.min(total - 1, current + 1);
    if (start > 2)
        out.push('…');
    for (let i = start; i <= end; i++)
        out.push(i);
    if (end < total - 1)
        out.push('…');
    out.push(total);
    return out;
}
//# sourceMappingURL=PagesListView.js.map