'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
// packages/ui/src/crud/components/EntityCardList.tsx
/**
 * @fileoverview Entity Card List Component
 * @description Card grid view for public/user-facing entity browsing.
 * Features: Responsive grid of cards with images, key fields, and navigation to detail pages.
 *
 * **Routing:** Convention basePath = `/${collection}`. View = basePath/:id.
 * Override basePath for nested routes; use onClick(id) to open sheet instead of navigating.
 *
 * @version 0.3.0
 * @since 0.0.1
 * @author AMBROISE PARK Consulting
 */
import { Heart } from 'lucide-react';
import { useMemo, useCallback } from 'react';
import { Card, Grid, Stack, Text, Skeleton, Section, Button, } from '@donotdev/components';
import { useTranslation, getListCardFieldNames, useBreakpoint, } from '@donotdev/core';
import { isCrudModuleAvailable, useCrudCardList, EntityFilters, useEntityFavorites, useCrudFilters, } from '../crudImports';
import { CrudCard } from './CrudCardLink';
import { useNavigate } from '../../routing';
/**
 * Resolve skeleton slots from entity shape — mirrors CrudCard's useResolvedSlots exactly.
 * Returns the actual field names per slot so skeletons render the same structure as real cards.
 */
function resolveSkeletonSlots(entity) {
    const l = entity.listCardFields;
    if (l && !Array.isArray(l)) {
        const layout = l;
        return {
            titleFields: layout.title ?? [],
            subtitleFields: layout.subtitle ?? [],
            contentFields: layout.content ?? [],
            footerFields: layout.footer ?? [],
        };
    }
    const fieldsToShow = getListCardFieldNames(entity);
    const isImage = (name) => {
        const type = entity.fields[name]?.type;
        return type === 'image' || type === 'images';
    };
    const other = fieldsToShow.filter((n) => !isImage(n));
    const images = fieldsToShow.filter(isImage);
    return {
        titleFields: other.length > 0 ? [other[0]] : [],
        subtitleFields: [],
        contentFields: [...other.slice(1, 4), ...images],
        footerFields: [],
    };
}
/**
 * Skeleton grid — renders the same Card structure as CrudCard but with
 * Skeleton elements instead of real data. No hardcoded sizes; the Card's
 * own layout determines the shape.
 */
const BREAKPOINT_INDEX = {
    mobile: 0,
    tablet: 1,
    laptop: 2,
    desktop: 3,
};
function CardListSkeleton({ cols, entity, }) {
    const slots = resolveSkeletonSlots(entity);
    const bp = useBreakpoint('current');
    const currentCols = (Array.isArray(cols)
        ? cols[BREAKPOINT_INDEX[bp] ?? 3]
        : cols) ?? 1;
    const count = currentCols * 3;
    const isImage = (name) => {
        const type = entity.fields[name]?.type;
        return type === 'image' || type === 'images';
    };
    const contentNode = slots.contentFields.length > 0 ? (_jsx(Stack, { direction: "column", gap: "tight", children: slots.contentFields.map((fieldName) => isImage(fieldName) ? (_jsx(Skeleton, { height: 120 }, fieldName)) : (_jsxs("div", { children: [_jsx(Text, { level: "small", variant: "muted", children: _jsx(Skeleton, {}) }), _jsx(Text, { children: _jsx(Skeleton, {}) })] }, fieldName))) })) : undefined;
    const footerNode = slots.footerFields.length > 0 ? (_jsx(Text, { level: "small", children: _jsx(Skeleton, {}) })) : undefined;
    return (_jsx(Grid, { cols: cols, children: Array.from({ length: count }, (_, i) => (_jsx(Card, { title: _jsx(Skeleton, {}), subtitle: slots.subtitleFields.length > 0 ? _jsx(Skeleton, {}) : undefined, content: contentNode, footer: footerNode, elevated: true }, i))) }));
}
/**
 * Entity Card List Component - Card grid view for public/user-facing browsing
 *
 * Features:
 * - Responsive card grid layout
 * - Image + key fields display
 * - Click card to navigate to detail
 * - Simple formatted text display (labels + values)
 * - Empty state handling
 * - Auto-routing when handler not provided
 */
export function EntityCardList({ entity, basePath, onClick, cols = [1, 2, 3, 4], staleTime = 1000 * 60 * 30, // 30 minutes default cache
queryOptions, filter, hideFilters = false, resultLabel, tone, collapsible = false, defaultOpen, }) {
    // Safe guard: isCrudModuleAvailable is a module-level constant (immutable after load).
    // eslint-disable-next-line react-hooks/rules-of-hooks
    if (!isCrudModuleAvailable)
        return null;
    const navigate = useNavigate();
    const base = basePath ?? `/${entity.collection}`;
    // useCrudCardList -> handles fetching + client-side filter/search/sort via `processed`
    const { items: rawData, processed, loading, } = useCrudCardList(entity, { staleTime, queryOptions });
    // Favorites - always enabled, no props needed
    const { isFavorite, toggleFavorite, favoritesFilter } = useEntityFavorites({
        collection: entity.collection,
    });
    // Favorites toggle from CrudStore (persists across navigation)
    const { showFavoritesOnly, setShowFavoritesOnly } = useCrudFilters({
        collection: entity.collection,
    });
    // Apply UI-specific filters (favorites, consumer filter prop) on top of processed
    // Favorites always sort to front; when showFavoritesOnly, only favorites are shown
    let data = processed;
    if (showFavoritesOnly) {
        data = data.filter(favoritesFilter);
    }
    if (filter) {
        data = data.filter(filter);
    }
    // Sort favorites to front (stable sort preserves relative order within each group)
    data = data.toSorted((a, b) => {
        const aFav = isFavorite(String(a.id)) ? 0 : 1;
        const bFav = isFavorite(String(b.id)) ? 0 : 1;
        return aFav - bFav;
    });
    // Entity + crud namespaces so formatValue can resolve crud:price.* etc.
    const { t } = useTranslation([entity.namespace, 'crud']);
    const { t: tCrud } = useTranslation('crud');
    // Card click: onClick(id) if provided, else navigate to basePath/:id
    const handleView = useCallback((id) => {
        if (onClick) {
            onClick(id);
        }
        else {
            navigate(`${base}/${id}`);
        }
    }, [base, navigate, onClick]);
    // Flat field names for filters (works with both string[] and ListCardLayout)
    const fieldsToFilter = useMemo(() => getListCardFieldNames(entity), [entity]);
    const entityName = t('name', { defaultValue: entity.name });
    return (_jsxs(_Fragment, { children: [!hideFilters && (_jsx(Section, { title: tCrud('filters.title', {
                    entity: entityName,
                    defaultValue: `Browse ${entityName} - Filters`,
                }), collapsible: collapsible, defaultOpen: defaultOpen, tone: tone, children: _jsx(Card, { children: _jsxs(Stack, { direction: "column", children: [_jsx(Button, { variant: showFavoritesOnly ? 'primary' : 'outline', icon: _jsx(Heart, { size: 18 }), onClick: () => setShowFavoritesOnly(!showFavoritesOnly), children: showFavoritesOnly
                                    ? tCrud('favorites.showAll', { defaultValue: 'Show All' })
                                    : tCrud('favorites.showFavorites', {
                                        defaultValue: 'Show Favorites',
                                    }) }), _jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: fieldsToFilter })] }) }) })), _jsx(Section, { title: loading
                    ? tCrud('results.title.fetching', { defaultValue: 'Fetching...' })
                    : resultLabel
                        ? resultLabel(data.length)
                        : tCrud('results.title.count', {
                            count: data.length,
                            defaultValue: data.length === 1
                                ? 'Found 1 occurrence'
                                : `Found ${data.length} occurrences`,
                        }), collapsible: collapsible, defaultOpen: collapsible ? true : undefined, tone: tone, children: loading ? (_jsx(CardListSkeleton, { cols: cols, entity: entity })) : data.length === 0 ? (_jsxs(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)', textAlign: 'center' }, children: [_jsx(Text, { level: "h3", style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.title', {
                                defaultValue: `No ${entity.name.toLowerCase()} found`,
                            }) }), _jsx(Text, { style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.description', {
                                defaultValue: `No ${entity.name.toLowerCase()} available at this time.`,
                            }) })] })) : (_jsx(Grid, { cols: cols, children: data.map((item) => {
                        const itemIsFavorite = isFavorite(item.id);
                        const detailHref = onClick ? undefined : `${base}/${item.id}`;
                        return (_jsx(CrudCard, { item: item, entity: entity, detailHref: detailHref, onClick: onClick ? () => handleView(item.id) : undefined, renderActions: _jsx(Heart, { fill: itemIsFavorite ? '#ef4444' : '#ffffff', stroke: itemIsFavorite ? '#ef4444' : 'var(--muted-foreground)', onClick: (e) => {
                                    e.preventDefault();
                                    e.stopPropagation();
                                    toggleFavorite(item.id);
                                }, style: {
                                    cursor: 'pointer',
                                    width: 'var(--icon-md)',
                                    height: 'var(--icon-md)',
                                    transition: 'fill 0.2s, stroke 0.2s',
                                }, "aria-label": itemIsFavorite
                                    ? tCrud('favorites.remove', {
                                        defaultValue: 'Remove from favorites',
                                    })
                                    : tCrud('favorites.add', {
                                        defaultValue: 'Add to favorites',
                                    }) }) }, item.id));
                    }) })) })] }));
}
