 
// Force Vite HMR reload

import React, { useState, useRef, useEffect, useMemo, useCallback, lazy } from 'react';
import { SEOHead } from '../components/seo/SEOHead';
import { RecipeCard } from '../components/recipe/RecipeCard';
import { Sparkles, CalendarDays, ShoppingBag, Package } from 'lucide-react';
import { useNavigate, useNavigationType, useLocation, Link } from 'react-router-dom';
import { RecipeGridSkeleton } from '../components/ui/Skeleton';
import { filterRecipesByActiveFilters } from '../components/recipe/RecipeFilters';
import { safeStorage } from '../utils/safeStorage';
import { RecipeSearchFilter } from '../components/recipe/RecipeSearchFilter';
import recipeCache from '../services/recipeCache';
import contentService from '../services/contentService';
import { CMSInlineEditor } from '../components/cms/CMSInlineEditor';
import { useAppContext } from '../context/AppContext';
import { calculatePersonalMatchScore } from '../utils/personalMatch';
import { trackEvent } from '../utils/pageMetrics';
import { useScrollRestoration } from '../hooks/useScrollRestoration';
import { RecipeHubSiloLinks } from '../components/seo/RecipeHubSiloLinks';
import { LazyHomeSocialSections } from '../components/home/LazyHomeSocialSections';
import { StoryRings } from '../components/home/StoryRings';
import { PullToRefresh } from '../components/ui/PullToRefresh';
import { PersonalHealthDashboard } from '../components/home/PersonalHealthDashboard';
import PremiumSearchBanner from '../components/ui/PremiumSearchBanner';
import { RecipeEmptyState } from '../components/recipe/RecipeEmptyState';
import { optimizedImg } from '../utils/optimizedImg';
import { useIdleImagePreload } from '../hooks/useIdleImagePreload';
import { PremiumBentoTile } from '../components/ui/PremiumBentoTile';
import './Recipes.css';
import './Recipes.polish.css';
import './Home.polish.css';

const RecipesSeoBlock = lazy(() => import('../components/seo/RecipesSeoBlock').then(m => ({ default: m.RecipesSeoBlock })));

// Minimal boundary: swallow lazy-chunk load failures for the SEO block so they never
// surface above-the-fold. Returns null on error — the block is purely informational.
class LazyBlockBoundary extends React.Component {
    constructor(props) { super(props); this.state = { failed: false }; }
    static getDerivedStateFromError() { return { failed: true }; }
    componentDidCatch(err) { console.warn('[RecipesSeoBlock] lazy-load failed:', err); }
    render() { return this.state.failed ? null : this.props.children; }
}


const PREMIUM_TOOLS = [
    { name: 'Wochenplaner', desc: 'Mahlzeiten planen', image: '/images/features/wochenplaner_hero.webp', link: '/wochenplan', icon: CalendarDays, color: '#3b82f6' },
    { name: 'Vorratsschrank', desc: 'Vorräte im Blick', image: '/images/features/vorratsschrank_hero.webp', link: '/vorratsschrank', icon: Package, color: '#10b981' },
    { name: 'Einkaufsliste', desc: 'Smart sortiert', image: '/images/features/einkaufsliste_hero.webp', link: '/einkaufsliste', icon: ShoppingBag, color: '#a855f7' },
    { name: 'KI-Generator', desc: 'Rezepte erstellen', image: '/images/features/ki_generator_hero.webp', link: '/rezept-generator', icon: Sparkles, color: '#f59e0b' }
];


export function Recipes() {
    const resultsRef = useRef(null);
    const navigate = useNavigate();
    const navType = useNavigationType();
    const { pantryItems, user } = useAppContext();
    const location = useLocation();
    const queryParams = new URLSearchParams(location.search);
    const pantryMode = queryParams.get('pantry') === 'true' && pantryItems.length > 0;
    const urlPage = parseInt(queryParams.get('page'), 10);

    const [searchQuery, setSearchQuery] = useState(() => {
        // Priority: URL > sessionStorage > default
        const urlQ = queryParams.get('q');
        if (urlQ !== null) return urlQ;
        const stored = safeStorage.session.get('recipes_searchQuery');
        return stored || '';
    });
    const [searchInput, setSearchInput] = useState(searchQuery);
    const searchTimeoutRef = useRef(null);
    const [activeFilters, setActiveFilters] = useState(() => {
        // Priority: URL > sessionStorage > default
        const urlFilter = queryParams.get('filter');
        if (urlFilter) return urlFilter.split(',').filter(Boolean);
        const stored = safeStorage.session.getJSON('recipes_activeFilters');
        return Array.isArray(stored) ? stored : [];
    });
    const hasProfile = user?.goals?.length > 0 || user?.diets?.length > 0;
    const [sortBy, setSortBy] = useState(() => {
        const urlSort = queryParams.get('sort');
        if (urlSort) return urlSort;
        return safeStorage.local.get('recipes_sortBy') || (hasProfile ? 'forYou' : 'relevant');
    });
    const [sortDirection, setSortDirection] = useState(() => {
        const urlDir = queryParams.get('dir');
        if (urlDir === 'asc' || urlDir === 'desc') return urlDir;
        return safeStorage.local.get('recipes_sortDirection') || 'desc';
    });

    // ── URL Persistence: sync filter/search/sort state to URL on change ──
    // Uses history.replaceState to avoid polluting navigation history.
    // Supports bookmarking, sharing, and page-reload restoration.
    useEffect(() => {
        try {
            const params = new URLSearchParams(window.location.search);
            // filters
            if (activeFilters.length > 0) {
                params.set('filter', activeFilters.join(','));
            } else {
                params.delete('filter');
            }
            // search
            if (searchQuery) {
                params.set('q', searchQuery);
            } else {
                params.delete('q');
            }
            // sort (only if non-default). Treat both 'forYou' and 'relevant' as defaults —
            // they're interchangeable based on whether the user has a profile.
            const isDefaultSort = !sortBy || sortBy === 'forYou' || sortBy === 'relevant';
            if (!isDefaultSort) {
                params.set('sort', sortBy);
            } else {
                params.delete('sort');
            }
            // direction (only if not default 'desc')
            if (sortDirection && sortDirection !== 'desc') {
                params.set('dir', sortDirection);
            } else {
                params.delete('dir');
            }
            const newQuery = params.toString();
            const newUrl = `${window.location.pathname}${newQuery ? `?${newQuery}` : ''}${window.location.hash}`;
            if (newUrl !== `${window.location.pathname}${window.location.search}${window.location.hash}`) {
                window.history.replaceState(null, '', newUrl);
            }
        } catch (err) {
            // Silently ignore — URL sync is a nice-to-have, not critical
            console.debug('[URL sync] skipped:', err);
        }
    }, [activeFilters, searchQuery, sortBy, sortDirection, hasProfile]);



    const [visibleCount, setVisibleCount] = useState(() => {
        if (!isNaN(urlPage) && urlPage > 1) {
            return urlPage * 8;
        }
        const cameFromRecipeDetail = safeStorage.session.get('recipes_cameFromRecipeDetail') === 'true';
        if (cameFromRecipeDetail && navType === 'POP') {
            const saved = safeStorage.session.get('recipes_visibleCount');
            return saved ? parseInt(saved, 10) : 8;
        }
        safeStorage.session.remove('recipes_visibleCount');
        safeStorage.session.remove('recipes_scrollY'); // Old manual key cleanup
        safeStorage.session.remove('recipes_cameFromRecipeDetail');
        return 8;
    });
    // Progressive activation: cards at index >= activatedCount render as skeletons
    // for one paint after visibleCount grows. Gives perceived responsiveness on "Mehr anzeigen".
    const [activatedCount, setActivatedCount] = useState(() => visibleCount);
    useEffect(() => {
        if (activatedCount === visibleCount) return;
        if (activatedCount > visibleCount) {
            setActivatedCount(visibleCount);
            return;
        }
        let raf2 = 0;
        const raf1 = requestAnimationFrame(() => {
            raf2 = requestAnimationFrame(() => setActivatedCount(visibleCount));
        });
        return () => {
            cancelAnimationFrame(raf1);
            if (raf2) cancelAnimationFrame(raf2);
        };
    }, [visibleCount, activatedCount]);

    const scrollToResults = useCallback(() => {
        // Only auto-scroll on mobile, as desktop has enough screen estate
        if (window.innerWidth >= 1024) return;

        // Use timeout to ensure the DOM has updated and results-count is visible
        setTimeout(() => {
            if (resultsRef.current) {
                // On mobile, the sticky search bar + filter pills is around 130-150px. 
                // Using scrollIntoView might put the element UNDER the sticky bar.
                // We use a larger negative offset so it definitely stops above the filters.
                const yOffset = -150;
                const y = resultsRef.current.getBoundingClientRect().top + window.pageYOffset + yOffset;
                window.scrollTo({ top: y, behavior: 'smooth' });
            }
        }, 100);
    }, [resultsRef]);

    const [dbRecipes, setDbRecipes] = useState(recipeCache.getCached() || []);
    const [loading, setLoading] = useState(!recipeCache.getCached());
    const [initialLoadDone, setInitialLoadDone] = useState(false);
    const [isFullyLoaded, setIsFullyLoaded] = useState(recipeCache.getCached() ? recipeCache.isFullyLoaded : false);

    // Recipe count per tag — for showing "Glutenfrei · 24" in filter dropdowns.
    // Only compute once the full dataset is loaded, otherwise counts reflect
    // just the 24-recipe initial batch and mislead the user.
    const tagCounts = useMemo(() => {
        if (!isFullyLoaded) return {};
        const counts = {};
        for (const r of dbRecipes) {
            if (r.tags) {
                for (const tag of r.tags) {
                    counts[tag] = (counts[tag] || 0) + 1;
                }
            }
        }
        return counts;
    }, [dbRecipes, isFullyLoaded]);
    const [seoVisible, setSeoVisible] = useState(false);
    const seoTriggerRef = useRef(null);
    const [showFullGrid, setShowFullGrid] = useState(false);
    const gridDeferredRef = useRef(null);

    const [isScrolled, setIsScrolled] = useState(false);
    const searchRowRef = useRef(null);

    useEffect(() => {
        const handleScroll = () => {
            if (searchRowRef.current) {
                // Determine if element has reached its sticky offset (72px desktop / 56px mobile)
                // We use 75px as a safe threshold for both.
                const rect = searchRowRef.current.getBoundingClientRect();
                setIsScrolled(rect.top <= 75);
            } else {
                setIsScrolled(window.scrollY > 20);
            }
        };
        window.addEventListener('scroll', handleScroll, { passive: true });
        handleScroll(); // init
        return () => window.removeEventListener('scroll', handleScroll);
    }, []);
    // Pre-compute a search index: one normalized string per recipe (title + ingredients)
    // This avoids running .toLowerCase().replace() on every keystroke for every recipe
    const searchIndex = useMemo(() => {
        return dbRecipes.map(recipe => {
            const titleStr = (recipe.title || '').toLowerCase().replace(/[-\s]/g, '');
            const ingredientStr = Array.isArray(recipe.ingredients)
                ? recipe.ingredients.map(i => (i || '').toLowerCase().replace(/[-\s]/g, '')).join('|')
                : '';
            return titleStr + '|' + ingredientStr;
        });
    }, [dbRecipes]);

    // Apply scroll restoration global hook — only depend on loading, NOT dbRecipes.length,
    // to avoid re-triggering scroll restoration when background fetch completes.
    useScrollRestoration('recipes_main_scrollY', true, [loading]);

    // Debounced sessionStorage writes — single timer replaces 5 synchronous writes per interaction
    useEffect(() => {
        const timer = setTimeout(() => {
            safeStorage.session.set('recipes_visibleCount', visibleCount.toString());
            safeStorage.session.setJSON('recipes_activeFilters', activeFilters);
            safeStorage.session.set('recipes_searchQuery', searchQuery);
            safeStorage.local.set('recipes_sortBy', sortBy);
            safeStorage.local.set('recipes_sortDirection', sortDirection);
        }, 300);
        return () => clearTimeout(timer);
    }, [visibleCount, activeFilters, searchQuery, sortBy, sortDirection]);

    const handleSearchChange = useCallback((e) => {
        const value = e.target.value;
        setSearchInput(value);
        if (searchTimeoutRef.current) clearTimeout(searchTimeoutRef.current);
        searchTimeoutRef.current = setTimeout(() => {
            setSearchQuery(value);
            setVisibleCount(8);
            safeStorage.session.remove('recipes_main_scrollY');
            safeStorage.session.remove('recipes_visibleCount');
            if (value) {
                scrollToResults();
            } else {
                window.scrollTo({ top: 0, behavior: 'smooth' });
            }
        }, 300);
    }, [scrollToResults]);

    // Stable callbacks for child components — prevents re-renders of MobileFilterSheet etc.
    const handleSetSortBy = useCallback((val) => {
        setSortBy(val);
        setVisibleCount(8);
        safeStorage.session.remove('recipes_main_scrollY');
        safeStorage.session.remove('recipes_visibleCount');
        scrollToResults();
    }, [scrollToResults]);

    const handlePantryToggle = useCallback(() => {
        if (pantryMode) navigate('/'); else navigate('/?pantry=true');
    }, [navigate, pantryMode]);



    // Progressive Data Hydration – uses singleton recipeCache (shared with HomeSocialSections)
    // Phase 1: Load a small initial batch (24 recipes) for instant rendering
    // Phase 2: Full dataset loads in background via recipeCache.getAll()
    useEffect(() => {
        let cancelled = false;
        let unsubscribe = null;
        const subscribeOnce = () => {
            if (unsubscribe) return; // invariant: at most one listener per mount
            unsubscribe = recipeCache.onFullLoad((fullData) => {
                if (cancelled) return;
                setDbRecipes(fullData);
                setIsFullyLoaded(true);
            });
        };

        const fetchRecipes = async () => {
            const cached = recipeCache.getCached();
            if (cached && cached.length > 0) {
                setDbRecipes(cached);
                setLoading(false);
                setIsFullyLoaded(recipeCache.isFullyLoaded);
                requestAnimationFrame(() => { if (!cancelled) setInitialLoadDone(true); });
                if (!recipeCache.isFullyLoaded) subscribeOnce();
                return;
            }

            setLoading(true);
            try {
                const initialData = await recipeCache.getInitialBatch(24, 'relevant');
                if (cancelled) return;
                setDbRecipes(initialData);
                setLoading(false);
                setIsFullyLoaded(false);
                requestAnimationFrame(() => { if (!cancelled) setInitialLoadDone(true); });
                subscribeOnce();
            } catch (err) {
                console.error('Error fetching recipes:', err);
                if (!cancelled) setLoading(false);
            }
        };

        fetchRecipes();

        return () => {
            cancelled = true;
            if (unsubscribe) { unsubscribe(); unsubscribe = null; }
        };
    }, []); // Only fetch on mount

    // Lazy-load the SEO block when user scrolls near it (saves DOMPurify from initial bundle)
    useEffect(() => {
        const el = seoTriggerRef.current;
        if (!el) return;
        const observer = new IntersectionObserver(
            ([entry]) => { if (entry.isIntersecting) { setSeoVisible(true); observer.disconnect(); } },
            { rootMargin: '200px' }
        );
        observer.observe(el);
        return () => observer.disconnect();
    }, [loading]);

    const hasCustomSort = (sortBy && sortBy !== 'forYou' && sortBy !== 'relevant') || (sortDirection && sortDirection !== 'desc');

    // Intersection Observer for deferred full grid rendering
    useEffect(() => {
        if (searchQuery || activeFilters.length > 0 || pantryMode || hasCustomSort) {
            setShowFullGrid(true);
            return;
        }

        const el = gridDeferredRef.current;
        if (!el) return;

        const observer = new IntersectionObserver(
            ([entry]) => {
                if (entry.isIntersecting) {
                    setShowFullGrid(true);
                    observer.disconnect();
                }
            },
            { rootMargin: '600px' }
        );
        observer.observe(el);
        return () => observer.disconnect();
    }, [searchQuery, activeFilters, pantryMode, hasCustomSort]);

    const handleRefresh = async () => {
        setLoading(true);
        try {
            const fullData = await recipeCache.getAll(true);
            setDbRecipes(fullData);
        } catch (err) {
            console.error('Refresh failed:', err);
        } finally {
            setLoading(false);
        }
    };




    const filteredRecipes = useMemo(() => {
        const searchStr = searchQuery.toLowerCase().replace(/[-\s]/g, '');

        // Use the pre-computed search index for blazing-fast filtering
        let result = dbRecipes.filter((recipe, idx) => {
            if (!searchStr) return true;
            return searchIndex[idx]?.includes(searchStr) ?? false;
        });

        // 2. Filter by active tags (includes user profile diets if pre-selected)
        result = filterRecipesByActiveFilters(result, activeFilters);

        // 3. Pantry Mode
        if (pantryMode && pantryItems.length > 0) {
            // Very simple pantry mode logic for this view: 
            // Score recipes by how many exact pantry items they contain
            const pantryNames = pantryItems.map(item => item.item.toLowerCase());
            const pantrySet = new Set(pantryNames);

            result = result.map(recipe => {
                let matchCount = 0;
                recipe.ingredients?.forEach(ing => {
                    if (ing.name) {
                        const ingLower = ing.name.toLowerCase();
                        if (pantrySet.has(ingLower) || pantryNames.some(pName => ingLower.includes(pName) || pName.includes(ingLower))) {
                            matchCount++;
                        }
                    }
                });
                return { ...recipe, _pantryScore: matchCount };
            }).filter(r => r._pantryScore > 0)
                .sort((a, b) => b._pantryScore - a._pantryScore);
        }

        // 3.5 Pre-compute match scores for sort + badge display
        const matchScoreCache = new WeakMap();
        if (user && (user.goals?.length > 0 || user.diets?.length > 0)) {
            for (const r of result) {
                matchScoreCache.set(r, calculatePersonalMatchScore(r, user) ?? 50);
            }
        }

        const ratingCache = new WeakMap();
        const getRating = (r) => {
            if (ratingCache.has(r)) return ratingCache.get(r);
            if (!r.comments || r.comments.length === 0) {
                ratingCache.set(r, 0);
                return 0;
            }
            const sum = r.comments.reduce((acc, c) => acc + (c.rating || 0), 0);
            const val = sum / r.comments.length;
            ratingCache.set(r, val);
            return val;
        };

        // 4. Sorting
        return result.sort((a, b) => {
            if (pantryMode && a._pantryScore !== b._pantryScore) {
                return 0; // Already sorted by score above
            }

            let valA, valB;

            switch (sortBy) {
                case 'duration':
                case 'time':
                    valA = (a.prepTime || 0) + (a.cookTime || 0);
                    valB = (b.prepTime || 0) + (b.cookTime || 0);
                    break;
                case 'calories':
                    valA = a.macros?.calories || 0;
                    valB = b.macros?.calories || 0;
                    break;
                case 'protein':
                    valA = a.macros?.protein || 0;
                    valB = b.macros?.protein || 0;
                    break;
                case 'carbs':
                    valA = a.macros?.carbs || 0;
                    valB = b.macros?.carbs || 0;
                    break;
                case 'fat':
                    valA = a.macros?.fat || 0;
                    valB = b.macros?.fat || 0;
                    break;
                case 'healthScore':
                    valA = a.macros?.healthScore || a.healthScore || 0;
                    valB = b.macros?.healthScore || b.healthScore || 0;
                    break;
                case 'antiInflammatory':
                    valA = a.macros?.antiInflammatoryScore || 0;
                    valB = b.macros?.antiInflammatoryScore || 0;
                    break;
                case 'antioxidant':
                    valA = a.macros?.antioxidantScore || 0;
                    valB = b.macros?.antioxidantScore || 0;
                    break;
                case 'longevity':
                    valA = a.macros?.longevityScore || 0;
                    valB = b.macros?.longevityScore || 0;
                    break;
                case 'hormoneBalance':
                    valA = a.macros?.hormoneBalanceScore || 0;
                    valB = b.macros?.hormoneBalanceScore || 0;
                    break;
                case 'glucoseStability':
                    valA = a.macros?.glucoseStabilityScore || 0;
                    valB = b.macros?.glucoseStabilityScore || 0;
                    break;
                case 'gutHealth':
                    valA = a.macros?.gutHealthScore || 0;
                    valB = b.macros?.gutHealthScore || 0;
                    break;
                case 'satiety':
                    valA = a.macros?.satietyScore || 0;
                    valB = b.macros?.satietyScore || 0;
                    break;
                case 'rating':
                    valA = getRating(a);
                    valB = getRating(b);
                    break;
                case 'likes':
                    valA = a._count?.savedBy || 0;
                    valB = b._count?.savedBy || 0;
                    break;
                case 'name':
                    return (a.title || '').localeCompare(b.title || '', 'de') * (sortDirection === 'asc' ? 1 : -1);
                case 'newest':
                    valA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
                    valB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
                    break;
                case 'forYou': {
                    // Sort by pre-computed personal match score (highest first)
                    const aMatch = matchScoreCache.get(a) ?? 50;
                    const bMatch = matchScoreCache.get(b) ?? 50;
                    if (aMatch !== bMatch) return bMatch - aMatch;
                    // Tiebreaker: healthScore
                    valA = a.macros?.healthScore || 0;
                    valB = b.macros?.healthScore || 0;
                    break;
                }
                case 'relevant':
                default: {
                    // Featured recipes first, ordered by featuredOrder
                    const aFeat = a.isFeatured ? 1 : 0;
                    const bFeat = b.isFeatured ? 1 : 0;
                    if (aFeat !== bFeat) return bFeat - aFeat;
                    // Among featured: sort by featuredOrder (lower = first)
                    if (aFeat && bFeat) {
                        const orderDiff = (a.featuredOrder || 0) - (b.featuredOrder || 0);
                        if (orderDiff !== 0) return orderDiff;
                    }
                    // Non-featured: composite of healthScore + recency
                    const aScore = (a.macros?.healthScore || a.healthScore || 0);
                    const bScore = (b.macros?.healthScore || b.healthScore || 0);
                    if (aScore !== bScore) return bScore - aScore;
                    // Tie-break by newest
                    const aDate = a.createdAt ? new Date(a.createdAt).getTime() : 0;
                    const bDate = b.createdAt ? new Date(b.createdAt).getTime() : 0;
                    if (bDate !== aDate) return bDate - aDate;

                    // Final tie-break by stable ID
                    return (a.id || '').localeCompare(b.id || '');
                }
            }

            if (valA === valB) {
                return (a.id || '').localeCompare(b.id || '');
            }

            if (sortDirection === 'asc') return valA - valB;
            return valB - valA;
        });
    }, [dbRecipes, searchIndex, searchQuery, activeFilters, pantryMode, pantryItems, sortBy, sortDirection, user]);

    // Track Searches 
    const filteredCount = filteredRecipes.length;
    useEffect(() => {
        if (!searchQuery || searchQuery.trim() === '') return;
        const timer = setTimeout(() => {
            const query = searchQuery.trim();
            trackEvent('search', query, '/rezepte', user?.id);
            // If search is complete and we have no results, track as zero-result search
            if (!loading && filteredCount === 0) {
                trackEvent('search_zero', query, '/rezepte', user?.id);
            }
        }, 1500);
        return () => clearTimeout(timer);
    }, [searchQuery, user?.id, loading, filteredCount]);



    const visibleRecipes = filteredRecipes.slice(0, visibleCount);
    const isHomeInitialLoad = loading && !searchQuery && activeFilters.length === 0 && !pantryMode;

    // Stable match-score lookup keyed by recipe.id so the numeric prop passed
    // to RecipeCard is referentially stable across re-renders (preserves React.memo).
    const hasProfileForScore = !!(user && (user.goals?.length > 0 || user.diets?.length > 0));
    const matchScoreById = useMemo(() => {
        if (!hasProfileForScore) return null;
        const map = new Map();
        for (const r of filteredRecipes) {
            if (r && r.id != null && !map.has(r.id)) {
                map.set(r.id, calculatePersonalMatchScore(r, user) ?? 50);
            }
        }
        return map;
    }, [filteredRecipes, user, hasProfileForScore]);

    // Preload all recipe images for the current batch during idle time so
    // scrolling never has to wait for network — images arrive from cache instantly.
    const visibleImageUrls = useMemo(
        () => visibleRecipes.map(r => r.image ? optimizedImg(r.image, { w: 400, q: 70 }) : null).filter(Boolean),
        [visibleRecipes]
    );
    useIdleImagePreload(visibleImageUrls);

    // Safely extract ALL profile settings (diets + goals) to prevent crashes
    const validDietsUi = user && Array.isArray(user.diets) ? user.diets.filter(d => typeof d === 'string' && d.trim() !== '') : [];
    const validGoalsUi = user && Array.isArray(user.goals) ? user.goals.filter(d => typeof d === 'string' && d.trim() !== '') : [];
    const strictDietsUserHas = [...validDietsUi, ...validGoalsUi];
    const hasStrictDiets = strictDietsUserHas.length > 0;

    let formatDiets = '';
    if (hasStrictDiets) {
        const firstDiet = strictDietsUserHas[0].charAt(0).toUpperCase() + strictDietsUserHas[0].slice(1);
        if (strictDietsUserHas.length > 1) {
            formatDiets = `${firstDiet} & ${strictDietsUserHas.length - 1} weitere`;
        } else {
            formatDiets = firstDiet;
        }
    }

    return (
        <PullToRefresh onRefresh={handleRefresh}>
            <div className="recipes-page container mb-0">
                <SEOHead
                    title={searchQuery ? `Suche: ${searchQuery}` : "Gesunde Rezepte – Low-Carb, Vegan & High-Protein"}
                    description="Entdecke maßgeschneiderte, gesunde Rezepte - von High-Protein bis Vegan. Generiere personalisierte Gerichte mit dem SmarTasty Rezeptfinder."
                    path="/"
                    schemaDetails={[
                        {
                            "@context": "https://schema.org",
                            "@type": "WebSite",
                            "name": "SmarTasty",
                            "url": "https://smartasty.de",
                            "potentialAction": {
                                "@type": "SearchAction",
                                "target": "https://smartasty.de/?q={search_term_string}",
                                "query-input": "required name=search_term_string"
                            }
                        },
                        {
                            "@context": "https://schema.org",
                            "@type": "Organization",
                            "name": "SmarTasty",
                            "url": "https://smartasty.de",
                            "logo": "https://smartasty.de/logo.png",
                            "description": "SmarTasty – Deine Plattform für gesunde, personalisierte Rezepte mit smartem Wochenplaner, Einkaufsliste und Vorratsschrank.",
                            "sameAs": []
                        }
                    ]}
                />
                <div className="recipes-desktop-hero" style={{ marginTop: '2rem', display: 'flex', gap: '2rem', alignItems: 'stretch' }}>
                    {/* Desktop Dashboard (~40%) */}
                    <div style={{ flex: '0 0 38%', display: 'flex', flexDirection: 'column' }}>
                        <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
                            <PersonalHealthDashboard user={user} loading={isHomeInitialLoad} />
                        </div>
                    </div>
                    {/* Desktop Premium Tools (~60%) */}
                    <div className="premium-tools-bento-wrapper" style={{ flex: '1 1 62%', minWidth: 0, margin: 0 }}>
                        <div className="premium-bento-grid">
                            {PREMIUM_TOOLS.map((tool, idx) => (
                                <PremiumBentoTile key={tool.name} tool={tool} idx={idx} priority={idx < 2} loading={isHomeInitialLoad} />
                            ))}
                        </div>
                    </div>
                </div>

                {/* ── Desktop: Search then Filter ── */}
                <div className="recipes-search-banner-container desktop-only" style={{ width: '100%', marginTop: '2.5rem' }}>
                    <PremiumSearchBanner
                        value={searchInput}
                        onChange={handleSearchChange}
                        onClear={() => {
                            setSearchInput('');
                            setSearchQuery('');
                            setVisibleCount(8);
                            window.scrollTo({ top: 0, behavior: 'smooth' });
                        }}
                    />
                </div>
                <div className="hide-on-mobile" style={{ marginTop: '1rem', marginBottom: '1.5rem' }}>
                    <RecipeSearchFilter
                        activeFilters={activeFilters}
                        setActiveFilters={(filters) => {
                            setActiveFilters(filters);
                            setVisibleCount(8);
                            safeStorage.session.remove('recipes_main_scrollY');
                            safeStorage.session.remove('recipes_visibleCount');
                        }}
                        sortBy={sortBy}
                        setSortBy={handleSetSortBy}
                        sortDirection={sortDirection}
                        setSortDirection={setSortDirection}
                        tagCounts={tagCounts}
                        resultCount={filteredRecipes.length}
                    />
                </div>
                {/* Split the hidden container so PersonalHealthDashboard is ABOVE the search bar */}
                <div>
                    <StoryRings />

                    {/* Mobile Only: Dashboard */}
                    <div className="recipes-mobile-hero" style={{ margin: '1.5rem 0 0.5rem' }}>
                        <PersonalHealthDashboard user={user} loading={isHomeInitialLoad} />
                    </div>



                    {/* Mobile Only: Premium App Store Style Tools Area */}
                    <div className="hide-on-desktop premium-tools-bento-wrapper" style={{ margin: '0 0 0.5rem 0' }}>
                        <div className="premium-bento-grid">
                            {PREMIUM_TOOLS.map((tool, idx) => (
                                <PremiumBentoTile key={tool.name} tool={tool} idx={idx} priority={idx < 2} loading={isHomeInitialLoad} />
                            ))}
                        </div>
                    </div>
                </div>


                {/* Mobile search */}
                <div ref={searchRowRef} className={`mobile-filter-trigger-row floating-search-row hide-on-desktop ${isScrolled ? 'is-scrolled' : ''}`}>
                    <PremiumSearchBanner
                        value={searchInput}
                        onChange={handleSearchChange}
                        onClear={() => {
                            setSearchInput('');
                            setSearchQuery('');
                            setVisibleCount(8);
                            window.scrollTo({ top: 0, behavior: 'smooth' });
                        }}
                    />
                </div>

                {/* Mobile filter bar — directly below search */}
                <div className="hide-on-desktop">
                    <RecipeSearchFilter
                        activeFilters={activeFilters}
                        setActiveFilters={(filters) => {
                            setActiveFilters(filters);
                            setVisibleCount(8);
                            safeStorage.session.remove('recipes_main_scrollY');
                            safeStorage.session.remove('recipes_visibleCount');
                        }}
                        sortBy={sortBy}
                        setSortBy={handleSetSortBy}
                        sortDirection={sortDirection}
                        setSortDirection={setSortDirection}
                        tagCounts={tagCounts}
                    />
                </div>

                {/* Safe Space now handled via Profile pill in RecipeSearchFilter */}

                <div className={`recipes-social-sections${(searchQuery || activeFilters.length > 0 || pantryMode || hasCustomSort) ? ' is-hidden' : ''}`}>

                    <LazyHomeSocialSections
                        loading={isHomeInitialLoad}
                        onShowAllNew={() => {
                            setSortBy('newest');
                            setSortDirection('desc');
                            document.querySelector('.recipes-result-count')?.scrollIntoView({ behavior: 'smooth' });
                        }}
                        onShowAllTrending={() => {
                            setSortBy('likes');
                            setSortDirection('desc');
                            document.querySelector('.recipes-result-count')?.scrollIntoView({ behavior: 'smooth' });
                        }}
                        onShowAllBySearch={(term) => {
                            setSearchInput(term);
                            setSearchQuery(term);
                            setActiveFilters([]);
                            setVisibleCount(12);
                            safeStorage.session.remove('recipes_main_scrollY');
                            safeStorage.session.remove('recipes_visibleCount');
                            setTimeout(() => {
                                document.querySelector('.recipes-result-count')?.scrollIntoView({ behavior: 'smooth' });
                            }, 100);
                        }}
                        onShowAllByFilter={(filterTag) => {
                            setSearchQuery('');
                            setActiveFilters([filterTag]);
                            setVisibleCount(12);
                            safeStorage.session.remove('recipes_main_scrollY');
                            safeStorage.session.remove('recipes_visibleCount');
                            setTimeout(() => {
                                document.querySelector('.recipes-result-count')?.scrollIntoView({ behavior: 'smooth' });
                            }, 100);
                        }}
                        onShowAllBySort={(sort, direction) => {
                            setSearchQuery('');
                            setActiveFilters([]);
                            setSortBy(sort);
                            setSortDirection(direction || 'desc');
                            setVisibleCount(12);
                            safeStorage.session.remove('recipes_main_scrollY');
                            safeStorage.session.remove('recipes_visibleCount');
                            setTimeout(() => {
                                document.querySelector('.recipes-result-count')?.scrollIntoView({ behavior: 'smooth' });
                            }, 100);
                        }}
                    />

                    {/* Visual marker for deferred grid loading */}
                    {!showFullGrid && <div ref={gridDeferredRef} style={{ height: '20px' }} />}

                </div>

                {(searchQuery || activeFilters.length > 0 || pantryMode || hasCustomSort || showFullGrid) && (
                    <>
                        {!loading && (
                            <div ref={resultsRef} className="recipes-result-count" style={{ padding: '0.75rem 0 0.25rem', opacity: 0.5 }}>
                                <span style={{ fontSize: '0.8rem', color: 'var(--text-secondary)' }}>
                                    {Math.min(visibleCount, filteredRecipes.length)} von {isFullyLoaded || activeFilters.length > 0 || searchQuery ? filteredRecipes.length : (recipeCache.totalCount || '...')} Rezepten
                                </span>
                            </div>
                        )}

                        {loading ? (
                            <RecipeGridSkeleton text="Lade Rezepte..." />
                        ) : (
                            <div className="recipes-grid">
                                {visibleRecipes.length > 0 ? (
                                    visibleRecipes.map((recipe, index) => {
                                        if (index >= activatedCount) {
                                            return (
                                                <div key={recipe.id} style={{ position: 'relative' }}>
                                                    <RecipeCard loading />
                                                </div>
                                            );
                                        }
                                        const matchScore = matchScoreById ? (matchScoreById.get(recipe.id) ?? null) : null;
                                        return (
                                            <div
                                                key={recipe.id}
                                                className={initialLoadDone && index < 8 ? undefined : 'recipe-card-animate'}
                                                style={{ position: 'relative' }}
                                            >
                                                <RecipeCard
                                                    recipe={recipe}
                                                    showMacros={false}
                                                    priority={index < 3}
                                                    showMatchScore={true}
                                                    matchScore={matchScore}
                                                    hideTags={true}
                                                />
                                            </div>
                                        );
                                    })
                                ) : (
                                    <div className="recipes-empty-state">
                                        <RecipeEmptyState
                                            type={pantryMode ? 'pantry' : (searchQuery ? 'search' : 'filter')}
                                            searchQuery={searchQuery}
                                            onResetFilters={() => setActiveFilters([])}
                                            onSearchClear={() => {
                                                setSearchInput('');
                                                setSearchQuery('');
                                                setVisibleCount(8);
                                            }}
                                            hasProfileFilters={hasStrictDiets}
                                        />
                                    </div>
                                )}
                            </div>
                        )}

                        {!loading && (visibleCount < filteredRecipes.length || (!isFullyLoaded && recipeCache.totalCount > visibleCount)) && (
                            <div className="recipes-load-more-container">
                                <Link
                                    to={`?page=${Math.floor(visibleCount / 8) + 1}`}
                                    onClick={(e) => {
                                        e.preventDefault();
                                        setVisibleCount(prev => prev + 12);
                                    }}
                                    className="btn btn-primary btn-md"
                                >
                                    <CMSInlineEditor contentKey="recipes.loadMore.btn" type="text" fallback="Mehr Rezepte anzeigen">
                                        <span>{contentService.get('recipes.loadMore.btn', 'Mehr Rezepte anzeigen')}</span>
                                    </CMSInlineEditor>
                                </Link>
                            </div>
                        )}
                    </>
                )}



                {/* Intersection Observer trigger — loads SEO block + DOMPurify only when scrolled near */}
                <div ref={seoTriggerRef} style={{ minHeight: 1 }} />
                {seoVisible && (
                    <LazyBlockBoundary>
                        <React.Suspense fallback={null}>
                            <RecipesSeoBlock />
                        </React.Suspense>
                    </LazyBlockBoundary>
                )}

                <RecipeHubSiloLinks />
            </div>
        </PullToRefresh>
    );
}
