import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/router';
import { isVariantAvailable } from '../lib/variantStock';
import {
  CatalogProductGrid,
  formatProductCount,
  type CatalogProduct,
} from './CatalogProductCard';

type Product = CatalogProduct;

type SortMode = 'sort_id' | 'newest' | 'cheapest' | 'most_expensive';

interface ProductListingProps {
  initialProducts?: Product[];
  showHeader?: boolean;
  sectionId?: string;
  dataSection?: string;
}

const PAGE_SIZE = 20;

const scrollToProductListing = (sectionId: string) => {
  window.requestAnimationFrame(() => {
    window.requestAnimationFrame(() => {
      document.getElementById(sectionId)?.scrollIntoView({ behavior: 'auto', block: 'start' });
    });
  });
};

const uniqueSorted = (values: string[]) => [...new Set(values.filter(Boolean))]
  .sort((a, b) => a.localeCompare(b, 'cs'));

const variantsFor = (
  product: Product,
  volumes: number[],
  minPrice: number | null,
  maxPrice: number | null,
) => product.variants.filter((variant) =>
  (!volumes.length || volumes.includes(variant.volumeMl))
  && (minPrice === null || Number(variant.currentPrice) >= minPrice)
  && (maxPrice === null || Number(variant.currentPrice) <= maxPrice)
);

const lowestPrice = (product: Product) => {
  const available = product.variants.filter((variant) => isVariantAvailable(variant, product.stock));
  const pool = available.length ? available : product.variants;
  return pool.length ? Math.min(...pool.map((variant) => Number(variant.currentPrice))) : Number.POSITIVE_INFINITY;
};

const ProductListing: React.FC<ProductListingProps> = ({
  initialProducts,
  showHeader = true,
  sectionId = 'vune',
  dataSection = 'all-products',
}) => {
  const router = useRouter();
  const [products, setProducts] = useState<Product[]>(initialProducts || []);
  const [loading, setLoading] = useState(!initialProducts);
  const [error, setError] = useState<string | null>(null);
  const [sortBy, setSortBy] = useState<SortMode>('sort_id');
  const [brands, setBrands] = useState<string[]>([]);
  const [brandSearch, setBrandSearch] = useState('');
  const [volumes, setVolumes] = useState<number[]>([]);
  const [badges, setBadges] = useState<string[]>([]);
  const [priceMin, setPriceMin] = useState('');
  const [priceMax, setPriceMax] = useState('');
  const [availableOnly, setAvailableOnly] = useState(false);
  const [filtersOpen, setFiltersOpen] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);
  const [urlStateReady, setUrlStateReady] = useState(false);
  const urlStateRestored = useRef(false);
  const skipNextFilterReset = useRef(false);
  const pendingPageScroll = useRef(false);

  useEffect(() => {
    if (!router.isReady || urlStateRestored.current) return;
    const value = (key: string) => {
      const raw = router.query[key];
      return Array.isArray(raw) ? raw[0] || '' : raw || '';
    };
    const list = (key: string) => value(key).split(',').map((item) => item.trim()).filter(Boolean);
    const requestedPage = Number(value('page'));
    const requestedSort = value('sort') as SortMode;
    const restoredPage = Number.isInteger(requestedPage) && requestedPage > 0 ? requestedPage : 1;
    skipNextFilterReset.current = true;
    pendingPageScroll.current = restoredPage > 1;
    setCurrentPage(restoredPage);
    setSortBy(['sort_id', 'newest', 'cheapest', 'most_expensive'].includes(requestedSort) ? requestedSort : 'sort_id');
    setBrands(list('brands'));
    setVolumes(list('volumes').map(Number).filter((item) => Number.isFinite(item) && item > 0));
    setBadges(list('badges'));
    setPriceMin(value('min'));
    setPriceMax(value('max'));
    setAvailableOnly(value('available') === '1');
    urlStateRestored.current = true;
    setUrlStateReady(true);
  }, [router.isReady, router.query]);

  useEffect(() => {
    if (initialProducts) {
      setProducts(initialProducts);
      setLoading(false);
      setError(null);
      return;
    }
    const loadProducts = async () => {
      try {
        setLoading(true);
        const response = await fetch('/api/products');
        if (!response.ok) throw new Error('Products request failed');
        setProducts(await response.json());
        setError(null);
      } catch {
        setError('Nepodařilo se načíst produkty');
      } finally {
        setLoading(false);
      }
    };
    void loadProducts();
  }, [initialProducts]);

  useEffect(() => {
    if (!filtersOpen) return;
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = ''; };
  }, [filtersOpen]);

  const brandOptions = useMemo(() => uniqueSorted(products.map((product) => product.brandName)), [products]);
  const visibleBrandOptions = useMemo(() => {
    const query = brandSearch.trim().toLocaleLowerCase('cs');
    return query ? brandOptions.filter((brand) => brand.toLocaleLowerCase('cs').includes(query)) : brandOptions;
  }, [brandOptions, brandSearch]);
  const volumeOptions = useMemo(() => [...new Set(products.flatMap((product) => product.variants
    .map((variant) => variant.volumeMl)))]
    .filter((volume) => volume > 0)
    .sort((a, b) => a - b), [products]);
  const badgeOptions = useMemo(() => uniqueSorted(products.flatMap((product) => product.badges?.map((badge) => badge.name) || [])), [products]);
  const priceRange = useMemo(() => {
    const prices = products.flatMap((product) => product.variants
      .map((variant) => Number(variant.currentPrice)));
    return prices.length ? { min: Math.floor(Math.min(...prices)), max: Math.ceil(Math.max(...prices)) } : { min: 0, max: 0 };
  }, [products]);

  const minPrice = priceMin.trim() === '' ? null : Number(priceMin);
  const maxPrice = priceMax.trim() === '' ? null : Number(priceMax);

  const filteredProducts = useMemo(() => products.filter((product) => {
    if (brands.length && !brands.includes(product.brandName)) return false;
    if (badges.length && !badges.some((badge) => product.badges?.some((item) => item.name === badge))) return false;
    const relevantVariants = variantsFor(product, volumes, minPrice, maxPrice);
    if (!relevantVariants.length) return false;
    if (availableOnly && !relevantVariants.some((variant) => isVariantAvailable(variant, product.stock))) return false;
    return true;
  }), [availableOnly, badges, brands, maxPrice, minPrice, products, volumes]);

  const sortedProducts = useMemo(() => [...filteredProducts].sort((a, b) => {
    if (sortBy === 'newest') return b.id - a.id;
    if (sortBy === 'cheapest') return lowestPrice(a) - lowestPrice(b);
    if (sortBy === 'most_expensive') return lowestPrice(b) - lowestPrice(a);
    return (a.sortOrder ?? a.id) - (b.sortOrder ?? b.id) || a.id - b.id;
  }), [filteredProducts, sortBy]);

  const totalPages = Math.max(1, Math.ceil(sortedProducts.length / PAGE_SIZE));
  const page = Math.min(currentPage, totalPages);
  const visibleProducts = sortedProducts.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
  const firstVisible = sortedProducts.length ? (page - 1) * PAGE_SIZE + 1 : 0;
  const lastVisible = Math.min(page * PAGE_SIZE, sortedProducts.length);
  const activeFilterCount = brands.length + volumes.length + badges.length
    + Number(minPrice !== null || maxPrice !== null)
    + Number(availableOnly);

  useEffect(() => {
    if (!urlStateReady) return;
    if (skipNextFilterReset.current) {
      skipNextFilterReset.current = false;
      return;
    }
    setCurrentPage(1);
  }, [availableOnly, badges, brands, priceMax, priceMin, urlStateReady, volumes]);

  useEffect(() => {
    if (!urlStateReady || !router.isReady) return;
    const query: Record<string, string> = {};
    if (currentPage > 1) query.page = String(currentPage);
    if (sortBy !== 'sort_id') query.sort = sortBy;
    if (brands.length) query.brands = brands.join(',');
    if (volumes.length) query.volumes = volumes.join(',');
    if (badges.length) query.badges = badges.join(',');
    if (priceMin.trim()) query.min = priceMin.trim();
    if (priceMax.trim()) query.max = priceMax.trim();
    if (availableOnly) query.available = '1';
    const currentPath = router.asPath.split('?')[0]?.split('#')[0] || '/';
    const currentParams = new URLSearchParams(router.asPath.split('?')[1]?.split('#')[0] || '');
    ['page', 'sort', 'brands', 'volumes', 'badges', 'min', 'max', 'available'].forEach((key) => currentParams.delete(key));
    Object.entries(query).forEach(([key, value]) => currentParams.set(key, value));
    const nextSearch = currentParams.toString();
    const currentSearch = new URLSearchParams(router.asPath.split('?')[1]?.split('#')[0] || '').toString();
    const currentHash = router.asPath.split('#')[1] || '';
    const nextUrl = `${currentPath}${nextSearch ? `?${nextSearch}` : ''}`;
    let cancelled = false;
    const syncUrlAndScroll = async () => {
      if (nextSearch !== currentSearch || currentHash === sectionId) {
        await router.replace(nextUrl, undefined, { shallow: true, scroll: false }).catch(() => false);
      }
      if (cancelled || !pendingPageScroll.current) return;
      pendingPageScroll.current = false;
      scrollToProductListing(sectionId);
    };
    void syncUrlAndScroll();
    return () => { cancelled = true; };
  }, [availableOnly, badges, brands, currentPage, priceMax, priceMin, router, sectionId, sortBy, urlStateReady, volumes]);

  useEffect(() => {
    if (urlStateReady && currentPage > totalPages) setCurrentPage(totalPages);
  }, [currentPage, totalPages, urlStateReady]);

  const toggleString = (value: string, current: string[], update: (items: string[]) => void) => {
    update(current.includes(value) ? current.filter((item) => item !== value) : [...current, value]);
  };

  const toggleVolume = (value: number) => {
    setVolumes((current) => current.includes(value) ? current.filter((item) => item !== value) : [...current, value]);
  };

  const clearFilters = () => {
    setBrands([]);
    setBrandSearch('');
    setVolumes([]);
    setBadges([]);
    setPriceMin('');
    setPriceMax('');
    setAvailableOnly(false);
  };

  const changePage = (nextPage: number) => {
    const resolvedPage = Math.max(1, Math.min(totalPages, nextPage));
    if (resolvedPage === currentPage) {
      scrollToProductListing(sectionId);
      return;
    }
    pendingPageScroll.current = true;
    setCurrentPage(resolvedPage);
  };

  if (loading) return <section className="w-full bg-luxury-dark py-20 text-center text-luxury-gold">Načítání produktů…</section>;
  if (error) return <section className="w-full bg-luxury-dark py-20 text-center text-red-400">{error}</section>;

  return (
    <section
      id={sectionId}
      className={showHeader
        ? 'w-full scroll-mt-28 bg-luxury-dark px-4 py-20 sm:px-6 lg:px-[5vw] lg:py-24'
        : 'w-full scroll-mt-28 bg-luxury-dark'}
      data-section={dataSection}
    >
      <div className="mx-auto max-w-[1600px]">
        {showHeader && (
          <header className="mb-10 flex items-end justify-between gap-6">
            <div>
              <p className="mb-2 text-xs font-bold uppercase tracking-[0.18em] text-luxury-gold">Naše kolekce</p>
              <h2 className="text-4xl font-black tracking-[-0.035em] text-luxury-light sm:text-5xl lg:text-6xl">Celé parfémy</h2>
            </div>
            <span className="hidden text-xs text-luxury-light/45 sm:block">{formatProductCount(products.length)}</span>
          </header>
        )}

        <div className="grid items-start gap-8 md:grid-cols-[210px_minmax(0,1fr)] lg:gap-[clamp(35px,4vw,65px)]">
          {filtersOpen && <button type="button" aria-label="Zavřít filtry" onClick={() => setFiltersOpen(false)} className="fixed inset-0 z-[70] bg-black/65 md:hidden" />}

          <aside className={`fixed inset-y-0 left-0 z-[80] w-[88%] max-w-sm overflow-y-auto bg-[#10110f] px-6 py-7 text-luxury-light shadow-2xl transition-transform duration-300 md:sticky md:top-[132px] md:z-0 md:block md:max-h-[calc(100vh-152px)] md:w-auto md:max-w-none md:translate-x-0 md:bg-transparent md:p-0 md:pr-2 md:shadow-none ${filtersOpen ? 'translate-x-0' : '-translate-x-full'}`}>
            <div className="flex items-start justify-between border-b border-luxury-light/15 pb-5">
              <div><p className="mb-1 text-[10px] font-bold uppercase tracking-[0.18em] text-luxury-light/45">Filtry</p><h3 className="text-xl font-semibold">Vyberte vůni</h3></div>
              <button type="button" onClick={() => setFiltersOpen(false)} className="grid h-10 w-10 place-items-center text-luxury-light md:hidden" aria-label="Zavřít filtry"><CloseIcon /></button>
            </div>

            <FilterGroup title="Značka" count={brands.length} defaultOpen>
              <label className="mb-3 flex h-10 items-center gap-2 border border-luxury-light/15 px-3 text-luxury-light/55">
                <SearchIcon />
                <input type="search" value={brandSearch} onChange={(event) => setBrandSearch(event.target.value)} placeholder="Hledat značku…" className="min-w-0 flex-1 bg-transparent text-sm text-luxury-light outline-none placeholder:text-luxury-light/35" />
                {brandSearch && <button type="button" onClick={() => setBrandSearch('')} aria-label="Vymazat hledání"><CloseIcon small /></button>}
              </label>
              <div className="grid max-h-52 gap-2.5 overflow-y-auto pr-2">
                {visibleBrandOptions.map((brand) => <FilterOption key={brand} checked={brands.includes(brand)} label={brand} onChange={() => toggleString(brand, brands, setBrands)} />)}
                {!visibleBrandOptions.length && <p className="text-xs text-luxury-light/40">Žádná značka nebyla nalezena.</p>}
              </div>
            </FilterGroup>

            <FilterGroup title="Objem" count={volumes.length}>
              <div className="grid grid-cols-2 gap-2.5">{volumeOptions.map((volume) => <FilterOption key={volume} checked={volumes.includes(volume)} label={`${volume} ml`} onChange={() => toggleVolume(volume)} />)}</div>
            </FilterGroup>

            <FilterGroup title="Cena" count={minPrice !== null || maxPrice !== null ? 1 : 0} defaultOpen>
              <div className="grid grid-cols-[1fr_auto_1fr] items-end gap-2">
                <PriceInput label="Od" value={priceMin} onChange={setPriceMin} placeholder={`${priceRange.min} Kč`} />
                <span className="pb-2.5 text-luxury-light/35">–</span>
                <PriceInput label="Do" value={priceMax} onChange={setPriceMax} placeholder={`${priceRange.max} Kč`} />
              </div>
            </FilterGroup>

            <label className="flex cursor-pointer items-center gap-2.5 border-b border-luxury-light/15 py-5 text-sm text-luxury-light/70"><input type="checkbox" checked={availableOnly} onChange={(event) => setAvailableOnly(event.target.checked)} className="h-4 w-4 accent-luxury-gold" />Pouze skladem</label>

            {badgeOptions.length > 0 && <FilterGroup title="Štítek" count={badges.length}><div className="grid gap-2.5">{badgeOptions.map((badge) => <FilterOption key={badge} checked={badges.includes(badge)} label={badge} onChange={() => toggleString(badge, badges, setBadges)} />)}</div></FilterGroup>}

            {activeFilterCount > 0 && <button type="button" onClick={clearFilters} className="mt-5 border-b border-luxury-light/70 pb-1 text-xs text-luxury-light/70 hover:text-luxury-gold">Zrušit všechny filtry</button>}
            <button type="button" onClick={() => setFiltersOpen(false)} className="mt-6 min-h-12 w-full bg-luxury-gold px-4 text-sm font-bold text-luxury-dark md:hidden">Zobrazit {sortedProducts.length} produktů</button>
          </aside>

          <div className="min-w-0">
            <div className="mb-6 flex flex-wrap items-center justify-between gap-3 text-xs text-luxury-light/45">
              <button type="button" onClick={() => setFiltersOpen(true)} className="inline-flex min-h-11 items-center gap-2 border border-luxury-light/20 px-4 text-sm text-luxury-light md:hidden"><FilterIcon /> Filtrovat {activeFilterCount > 0 && <b className="grid h-5 min-w-5 place-items-center rounded-full bg-luxury-gold px-1 text-[9px] text-luxury-dark">{activeFilterCount}</b>}</button>
              <span>{sortedProducts.length ? `${firstVisible}–${lastVisible} z ${sortedProducts.length} produktů` : '0 produktů'}</span>
              <label className="flex items-center gap-2"><span className="hidden sm:inline">Řazení</span><select value={sortBy} onChange={(event) => setSortBy(event.target.value as SortMode)} className="h-10 rounded-none border border-luxury-light/15 bg-luxury-dark px-3 pr-8 text-xs text-luxury-light outline-none"><option value="sort_id">Výchozí</option><option value="newest">Nejnovější</option><option value="cheapest">Nejlevnější</option><option value="most_expensive">Nejdražší</option></select></label>
            </div>

            {visibleProducts.length > 0 ? (
              <>
                <CatalogProductGrid
                  products={visibleProducts}
                  variantsForProduct={(product) => variantsFor(product, volumes, minPrice, maxPrice)}
                />
                {totalPages > 1 && <CatalogPagination page={page} totalPages={totalPages} onChange={changePage} />}
              </>
            ) : (
              <div className="grid min-h-80 place-items-center border-t border-luxury-light/15 text-center"><div><h3 className="text-xl font-semibold text-luxury-light">Žádné produkty neodpovídají výběru.</h3><p className="mt-2 text-sm text-luxury-light/45">Zkuste upravit zvolené filtry.</p><button type="button" onClick={clearFilters} className="mt-5 border-b border-luxury-gold pb-1 text-sm text-luxury-gold">Zrušit filtry</button></div></div>
            )}
          </div>
        </div>
      </div>
    </section>
  );
};

function FilterGroup({ title, count, defaultOpen = false, children }: { title: string; count: number; defaultOpen?: boolean; children: React.ReactNode }) {
  const [open, setOpen] = useState(defaultOpen);
  return <details open={open} onToggle={(event) => setOpen(event.currentTarget.open)} className="border-b border-luxury-light/15"><summary className="flex cursor-pointer list-none items-center justify-between py-4 text-xs font-bold uppercase tracking-[0.08em] text-luxury-light marker:hidden"><span className="flex items-center gap-2">{title}{count > 0 && <b className="grid h-[18px] min-w-[18px] place-items-center rounded-full bg-luxury-gold px-1 text-[9px] text-luxury-dark">{count}</b>}</span><span className="text-base font-normal text-luxury-light/55">{open ? '−' : '+'}</span></summary><div className="pb-5">{children}</div></details>;
}

function FilterOption({ checked, label, onChange, type = 'checkbox', name }: { checked: boolean; label: string; onChange: () => void; type?: 'checkbox' | 'radio'; name?: string }) {
  return <label className="flex cursor-pointer items-center gap-2.5 text-sm text-luxury-light/65 hover:text-luxury-light"><input type={type} name={name} checked={checked} onChange={onChange} className="h-4 w-4 flex-none accent-luxury-gold" /><span>{label}</span></label>;
}

function PriceInput({ label, value, placeholder, onChange }: { label: string; value: string; placeholder: string; onChange: (value: string) => void }) {
  return <label className="grid min-w-0 gap-1.5 text-[10px] text-luxury-light/45">{label}<input type="number" min="0" step="50" inputMode="numeric" value={value} onChange={(event) => onChange(event.target.value)} placeholder={placeholder} className="h-10 min-w-0 rounded-none border border-luxury-light/15 bg-transparent px-2 text-sm text-luxury-light outline-none focus:border-luxury-gold" /></label>;
}

function CatalogPagination({ page, totalPages, onChange }: { page: number; totalPages: number; onChange: (page: number) => void }) {
  const pages = [...new Set([1, page - 1, page, page + 1, totalPages].filter((value) => value >= 1 && value <= totalPages))].sort((a, b) => a - b);
  return <nav className="mt-14 grid grid-cols-[44px_1fr_44px] items-center gap-3 border-t border-luxury-light/15 pt-6 sm:grid-cols-[1fr_auto_1fr]" aria-label="Stránkování produktů"><button type="button" disabled={page === 1} onClick={() => onChange(page - 1)} className="flex min-h-11 items-center justify-center gap-2 border border-luxury-light/15 px-3 text-xs text-luxury-light disabled:opacity-30 sm:justify-self-start"><ChevronIcon direction="left" /><span className="hidden sm:inline">Předchozí</span></button><div className="flex items-center justify-center gap-1">{pages.map((value, index) => <React.Fragment key={value}>{index > 0 && value - pages[index - 1] > 1 && <span className="w-5 text-center text-luxury-light/35">…</span>}<button type="button" onClick={() => onChange(value)} aria-current={value === page ? 'page' : undefined} className={`h-10 w-10 text-xs ${value === page ? 'bg-luxury-gold font-bold text-luxury-dark' : 'text-luxury-light/55 hover:border hover:border-luxury-light/20'}`}>{value}</button></React.Fragment>)}</div><button type="button" disabled={page === totalPages} onClick={() => onChange(page + 1)} className="flex min-h-11 items-center justify-center gap-2 border border-luxury-light/15 px-3 text-xs text-luxury-light disabled:opacity-30 sm:justify-self-end"><span className="hidden sm:inline">Další</span><ChevronIcon direction="right" /></button></nav>;
}

function SearchIcon() { return <svg className="h-4 w-4 flex-none" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d="m21 21-4.35-4.35m1.35-5.65a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z" /></svg>; }
function CloseIcon({ small = false }: { small?: boolean }) { return <svg className={small ? 'h-3.5 w-3.5' : 'h-5 w-5'} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d="M6 6l12 12M18 6 6 18" /></svg>; }
function FilterIcon() { return <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.7} d="M4 6h16M7 12h10M10 18h4" /></svg>; }
function ChevronIcon({ direction }: { direction: 'left' | 'right' }) { return <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d={direction === 'left' ? 'm15 18-6-6 6-6' : 'm9 18 6-6-6-6'} /></svg>; }

export default ProductListing;
