const { useState, useEffect, useRef, useCallback, createContext, useContext } = React;

const USER_TOKEN_KEY = 'beejou_user_token';
const LANG_KEY = 'beejou_lang';

// ===========================================================================
// Internationalization (EN / PL / UA)
// ===========================================================================
const LANGUAGES = [
  { code: 'en', label: 'EN', name: 'English' },
  { code: 'pl', label: 'PL', name: 'Polski' },
  { code: 'uk', label: 'UA', name: 'Українська' },
];

const TRANSLATIONS = {
  en: {
    'nav.home': 'Home', 'nav.collections': 'Collections', 'nav.about': 'About', 'nav.contact': 'Contact',
    'nav.signIn': 'Sign in', 'nav.cart': 'Cart', 'nav.account': 'Account',
    'tagline': 'JEWELRY',
    'card.new': 'New', 'card.freeDelivery': '📦 Free Delivery', 'card.deliveryTime': '5-7 business days',
    'card.view': 'View →',
    'rating.rateThis': 'Rate this item', 'rating.yourReview': 'Your review',
    'rating.final': "Thanks for rating — reviews can't be changed once submitted.",
    'rating.purchasedNote': 'You purchased this — share your experience. Your rating is final.',
    'rating.signInNote1': '⭐ Reviews are for verified buyers.',
    'rating.signInNote2': 'and once your order is complete you can leave a rating here.',
    'rating.buyNote': "⭐ You can rate this item once you've purchased it and your order is marked paid.",
    'rating.submit': 'Submit review', 'rating.saving': 'Saving…',
    'rating.noReviews': 'No reviews yet', 'rating.customerReviews': 'Customer reviews',
    'rating.commentPlaceholder': 'Add a comment (optional)',
    'detail.materials': 'Materials:', 'detail.dimensions': 'Dimensions:', 'detail.weight': 'Weight:',
    'detail.care': 'Care:', 'detail.delivery': 'Delivery:', 'detail.deliveryValue': '📦 Free delivery · 5-7 business days',
    'detail.addToCart': 'ADD TO CART', 'detail.inCart': 'In Cart',
    'filters.title': 'Filters', 'filters.clearAll': 'Clear all', 'filters.priceRange': 'Price Range', 'filters.color': 'Color',
    'cart.title': 'Shopping Cart', 'cart.empty': 'Your cart is empty', 'cart.items': 'Items in Cart',
    'cart.chooseDelivery': 'Choose Delivery', 'cart.yourDetails': 'Your Details', 'cart.shippingAddress': 'Shipping Address',
    'cart.subtotal': 'Subtotal:', 'cart.delivery': 'Delivery:', 'cart.total': 'Total:',
    'cart.secure': '🔒 Secure payment · order confirmed only after payment',
    'cart.proceed': 'PROCEED TO PAYMENT', 'cart.processing': 'PROCESSING…',
    'delivery.standard': 'Standard Delivery', 'delivery.standardDays': '5-7 business days',
    'delivery.express': 'Express Delivery', 'delivery.expressDays': '2-3 business days',
    'delivery.overnight': 'Overnight Delivery', 'delivery.overnightDays': 'Next business day',
    'form.fullName': 'Full name', 'form.email': 'Email address', 'form.street': 'Street address',
    'form.apt': 'Apartment, suite, etc. (optional)', 'form.city': 'City', 'form.state': 'State / Province',
    'form.postal': 'Postal code', 'form.country': 'Country',
    'collections.explore': 'Explore Our Collections', 'collections.subtitle': 'Discover jewelry curated by theme and inspiration',
    'shop.noProducts': 'No products found', 'shop.search': 'Search products...',
    'sort.featured': 'Featured', 'sort.priceLow': 'Price: Low to High', 'sort.priceHigh': 'Price: High to Low', 'sort.topRated': 'Top Rated',
    'hero.eyebrow': 'Handcrafted Beaded Jewelry', 'hero.title': 'Adornments with meaning',
    'hero.text': 'Every BeeJou piece is hand-beaded in small batches from natural gemstones, freshwater pearls, and premium seed beads — made to be worn, loved, and passed on.',
    'hero.cta': 'Shop the collection ↓',
    'about.title': 'Our Story',
    'about.p1': 'BeeJou began at a kitchen table, one bead at a time. What started as a quiet evening craft grew into a small studio devoted to handmade jewelry that feels personal — never mass-produced.',
    'about.p2': 'We choose materials we love: natural amethyst and turquoise, Japanese Miyuki beads, freshwater pearls, and hypoallergenic findings. Each design is created in limited quantities, so the piece you receive is genuinely yours.',
    'about.handmade': 'Handmade', 'about.handmadeText': 'Beaded by hand in small batches.',
    'about.natural': 'Natural materials', 'about.naturalText': 'Real gemstones, pearls & quality findings.',
    'about.lasting': 'Made to last', 'about.lastingText': 'Durable construction, lovingly finished.',
    'contact.title': 'Get in Touch', 'contact.lead': 'Questions, custom orders, or just to say hello — send us a note.',
    'contact.name': 'Your name (optional)', 'contact.email': 'Your email *', 'contact.message': 'Your message *',
    'contact.attach': '📎 Attach image', 'contact.send': 'Send message', 'contact.sending': 'Sending…',
    'contact.success': '✓ Thank you! Your message has been sent. We\'ll be in touch soon.', 'contact.sendAnother': 'Send another',
    'contact.needFields': 'Please add your email and a message.',
    'contact.sendingAs': 'Sending as',
    'login.subtitle': 'Sign in to save your favorites and track orders',
    'login.demoNote': 'Demo mode — Google not configured.', 'login.demoBtn': 'Continue as demo user',
    'account.title': 'My Account', 'account.logout': 'Log out', 'account.liked': 'Liked', 'account.orders': 'Orders',
    'account.noLikes': 'No liked items yet.', 'account.noOrders': 'No orders yet.',
    'account.rateHint': '★ Tap the stars to rate your purchases', 'account.yourRating': 'your rating',
    'account.address': 'Address', 'account.addressIntro': 'Save your shipping address to speed up checkout.', 'account.saveAddress': 'Save address', 'account.addressSaved': 'Saved',
    'account.rateIt': 'rate it', 'account.submit': 'Submit', 'account.saving': 'Saving…', 'account.item': 'item(s)',
    'footer': 'BeeeJou © 2024 | Handcrafted with ❤️ | ', 'footer.etsy': 'Visit Etsy Shop',
    'checkout.needEmail': 'Please enter your email to continue.',
    'checkout.needAddress': 'Please complete your shipping address (street, city, postal code, country).',
    'checkout.thankYou': 'Thank you! Payment received. Your order {ref} is confirmed.',
    'checkout.payNow': 'Pay ${amount} USD now? (demo payment — order {ref})',
    'off': 'OFF',
    'cat.All': 'All', 'cat.Bracelets': 'Bracelets', 'cat.Earrings': 'Earrings',
    'cat.Necklaces': 'Necklaces', 'cat.Sets': 'Sets', 'cat.Clearance': 'Clearance',
    'cat.Rings': 'Rings', 'cat.Anklets': 'Anklets',
    'coll.Gemstone Journey': 'Gemstone Journey', 'coll.Luminous Elegance': 'Luminous Elegance',
    'coll.Metallic Harmony': 'Metallic Harmony', 'coll.Prismatic Dreams': 'Prismatic Dreams',
    'coll.Summer Radiance': 'Summer Radiance', 'coll.Timeless Treasures': 'Timeless Treasures',
    'collDesc.Gemstone Journey': 'Discover the natural beauty of carefully selected gemstone beads in mesmerizing hues',
    'collDesc.Luminous Elegance': 'Sparkle and shine with pearls, crystals, and luminous designs',
    'collDesc.Metallic Harmony': 'Modern luxury through mixed metals and contemporary finishes',
    'collDesc.Prismatic Dreams': 'Celebrate color and creativity with vibrant, multi-hued pieces',
    'collDesc.Summer Radiance': 'Light, bright, and perfect for warm season style',
    'collDesc.Timeless Treasures': 'Vintage-inspired pieces with character and history',
    'cookie.text': 'We use local storage to keep your cart, favorites, and language preference, and a sign-in cookie if you log in. No tracking or advertising cookies are used.',
    'cookie.accept': 'Got it',
    'cookie.learn': 'Privacy',
    'consent.marketing': 'I\'d like to receive occasional offers and news by email. You can unsubscribe anytime.',
  },
  pl: {
    'nav.home': 'Strona główna', 'nav.collections': 'Kolekcje', 'nav.about': 'O nas', 'nav.contact': 'Kontakt',
    'nav.signIn': 'Zaloguj się', 'nav.cart': 'Koszyk', 'nav.account': 'Konto',
    'tagline': 'BIŻUTERIA',
    'card.new': 'Nowość', 'card.freeDelivery': '📦 Darmowa dostawa', 'card.deliveryTime': '5-7 dni roboczych',
    'card.view': 'Zobacz →',
    'rating.rateThis': 'Oceń produkt', 'rating.yourReview': 'Twoja recenzja',
    'rating.final': 'Dziękujemy za ocenę — recenzji nie można zmienić po wysłaniu.',
    'rating.purchasedNote': 'Kupiłeś ten produkt — podziel się wrażeniami. Ocena jest ostateczna.',
    'rating.signInNote1': '⭐ Recenzje są dla zweryfikowanych kupujących.',
    'rating.signInNote2': 'a po zrealizowaniu zamówienia możesz tu zostawić ocenę.',
    'rating.buyNote': '⭐ Możesz ocenić ten produkt po jego zakupie i opłaceniu zamówienia.',
    'rating.submit': 'Wyślij recenzję', 'rating.saving': 'Zapisywanie…',
    'rating.noReviews': 'Brak recenzji', 'rating.customerReviews': 'Recenzje klientów',
    'rating.commentPlaceholder': 'Dodaj komentarz (opcjonalnie)',
    'detail.materials': 'Materiały:', 'detail.dimensions': 'Wymiary:', 'detail.weight': 'Waga:',
    'detail.care': 'Pielęgnacja:', 'detail.delivery': 'Dostawa:', 'detail.deliveryValue': '📦 Darmowa dostawa · 5-7 dni roboczych',
    'detail.addToCart': 'DODAJ DO KOSZYKA', 'detail.inCart': 'W koszyku',
    'filters.title': 'Filtry', 'filters.clearAll': 'Wyczyść', 'filters.priceRange': 'Zakres cen', 'filters.color': 'Kolor',
    'cart.title': 'Koszyk', 'cart.empty': 'Twój koszyk jest pusty', 'cart.items': 'Produkty w koszyku',
    'cart.chooseDelivery': 'Wybierz dostawę', 'cart.yourDetails': 'Twoje dane', 'cart.shippingAddress': 'Adres dostawy',
    'cart.subtotal': 'Suma częściowa:', 'cart.delivery': 'Dostawa:', 'cart.total': 'Razem:',
    'cart.secure': '🔒 Bezpieczna płatność · zamówienie potwierdzane po opłaceniu',
    'cart.proceed': 'PRZEJDŹ DO PŁATNOŚCI', 'cart.processing': 'PRZETWARZANIE…',
    'delivery.standard': 'Dostawa standardowa', 'delivery.standardDays': '5-7 dni roboczych',
    'delivery.express': 'Dostawa ekspresowa', 'delivery.expressDays': '2-3 dni robocze',
    'delivery.overnight': 'Dostawa na następny dzień', 'delivery.overnightDays': 'Następny dzień roboczy',
    'form.fullName': 'Imię i nazwisko', 'form.email': 'Adres e-mail', 'form.street': 'Ulica i numer',
    'form.apt': 'Mieszkanie, lokal itp. (opcjonalnie)', 'form.city': 'Miasto', 'form.state': 'Województwo',
    'form.postal': 'Kod pocztowy', 'form.country': 'Kraj',
    'collections.explore': 'Odkryj nasze kolekcje', 'collections.subtitle': 'Biżuteria dobrana według tematu i inspiracji',
    'shop.noProducts': 'Nie znaleziono produktów', 'shop.search': 'Szukaj produktów...',
    'sort.featured': 'Polecane', 'sort.priceLow': 'Cena: rosnąco', 'sort.priceHigh': 'Cena: malejąco', 'sort.topRated': 'Najwyżej oceniane',
    'hero.eyebrow': 'Ręcznie robiona biżuteria koralikowa', 'hero.title': 'Ozdoby z znaczeniem',
    'hero.text': 'Każdy element BeeJou jest ręcznie nawlekany w małych partiach z naturalnych kamieni szlachetnych, pereł słodkowodnych i wysokiej jakości koralików — stworzony, by go nosić, kochać i przekazywać dalej.',
    'hero.cta': 'Zobacz kolekcję ↓',
    'about.title': 'Nasza historia',
    'about.p1': 'BeeJou zaczęło się przy kuchennym stole, koralik po koraliku. To, co było spokojnym wieczornym rękodziełem, przerodziło się w małą pracownię oddaną ręcznie robionej biżuterii — nigdy masowej.',
    'about.p2': 'Wybieramy materiały, które kochamy: naturalny ametyst i turkus, japońskie koraliki Miyuki, perły słodkowodne i hipoalergiczne elementy. Każdy projekt powstaje w ograniczonej ilości, więc otrzymany element jest naprawdę Twój.',
    'about.handmade': 'Ręcznie robione', 'about.handmadeText': 'Nawlekane ręcznie w małych partiach.',
    'about.natural': 'Naturalne materiały', 'about.naturalText': 'Prawdziwe kamienie, perły i wysokiej jakości elementy.',
    'about.lasting': 'Trwałe', 'about.lastingText': 'Solidne wykonanie, starannie wykończone.',
    'contact.title': 'Skontaktuj się', 'contact.lead': 'Pytania, zamówienia indywidualne lub po prostu cześć — napisz do nas.',
    'contact.name': 'Twoje imię (opcjonalnie)', 'contact.email': 'Twój e-mail *', 'contact.message': 'Twoja wiadomość *',
    'contact.attach': '📎 Załącz zdjęcie', 'contact.send': 'Wyślij wiadomość', 'contact.sending': 'Wysyłanie…',
    'contact.success': '✓ Dziękujemy! Twoja wiadomość została wysłana. Wkrótce się odezwiemy.', 'contact.sendAnother': 'Wyślij kolejną',
    'contact.needFields': 'Podaj swój e-mail i wiadomość.',
    'contact.sendingAs': 'Wysyłasz jako',
    'login.subtitle': 'Zaloguj się, aby zapisywać ulubione i śledzić zamówienia',
    'login.demoNote': 'Tryb demo — Google nieskonfigurowane.', 'login.demoBtn': 'Kontynuuj jako użytkownik demo',
    'account.title': 'Moje konto', 'account.logout': 'Wyloguj', 'account.liked': 'Ulubione', 'account.orders': 'Zamówienia',
    'account.noLikes': 'Brak ulubionych produktów.', 'account.noOrders': 'Brak zamówień.',
    'account.rateHint': '★ Kliknij gwiazdki, aby ocenić zakupy', 'account.yourRating': 'twoja ocena',
    'account.address': 'Adres', 'account.addressIntro': 'Zapisz adres dostawy, aby przyspieszyć zakupy.', 'account.saveAddress': 'Zapisz adres', 'account.addressSaved': 'Zapisano',
    'account.rateIt': 'oceń', 'account.submit': 'Wyślij', 'account.saving': 'Zapisywanie…', 'account.item': 'szt.',
    'footer': 'BeeeJou © 2024 | Tworzone z ❤️ | ', 'footer.etsy': 'Odwiedź sklep Etsy',
    'checkout.needEmail': 'Podaj swój e-mail, aby kontynuować.',
    'checkout.needAddress': 'Uzupełnij adres dostawy (ulica, miasto, kod pocztowy, kraj).',
    'checkout.thankYou': 'Dziękujemy! Płatność otrzymana. Twoje zamówienie {ref} jest potwierdzone.',
    'checkout.payNow': 'Zapłacić teraz ${amount} USD? (płatność demo — zamówienie {ref})',
    'off': 'TANIEJ',
    'cat.All': 'Wszystko', 'cat.Bracelets': 'Bransoletki', 'cat.Earrings': 'Kolczyki',
    'cat.Necklaces': 'Naszyjniki', 'cat.Sets': 'Komplety', 'cat.Clearance': 'Wyprzedaż',
    'cat.Rings': 'Pierścionki', 'cat.Anklets': 'Bransoletki na kostkę',
    'coll.Gemstone Journey': 'Podróż przez Kamienie', 'coll.Luminous Elegance': 'Świetlista Elegancja',
    'coll.Metallic Harmony': 'Metaliczna Harmonia', 'coll.Prismatic Dreams': 'Pryzmatyczne Marzenia',
    'coll.Summer Radiance': 'Letni Blask', 'coll.Timeless Treasures': 'Ponadczasowe Skarby',
    'collDesc.Gemstone Journey': 'Odkryj naturalne piękno starannie wybranych koralików z kamieni w urzekających odcieniach',
    'collDesc.Luminous Elegance': 'Lśnij blaskiem pereł, kryształów i świetlistych wzorów',
    'collDesc.Metallic Harmony': 'Nowoczesny luksus dzięki łączeniu metali i współczesnym wykończeniom',
    'collDesc.Prismatic Dreams': 'Świętuj kolor i kreatywność dzięki żywym, wielobarwnym wzorom',
    'collDesc.Summer Radiance': 'Lekkie, jasne i idealne na ciepłą porę roku',
    'collDesc.Timeless Treasures': 'Wzory inspirowane vintage, pełne charakteru i historii',
    'cookie.text': 'Używamy pamięci lokalnej, aby zapamiętać Twój koszyk, ulubione i język, oraz pliku logowania, jeśli się zalogujesz. Nie używamy plików śledzących ani reklamowych.',
    'cookie.accept': 'Rozumiem',
    'cookie.learn': 'Prywatność',
    'consent.marketing': 'Chcę otrzymywać okazjonalne oferty i nowości e-mailem. Możesz zrezygnować w każdej chwili.',
  },
  uk: {
    'nav.home': 'Головна', 'nav.collections': 'Колекції', 'nav.about': 'Про нас', 'nav.contact': 'Контакти',
    'nav.signIn': 'Увійти', 'nav.cart': 'Кошик', 'nav.account': 'Кабінет',
    'tagline': 'ПРИКРАСИ',
    'card.new': 'Нове', 'card.freeDelivery': '📦 Безкоштовна доставка', 'card.deliveryTime': '5-7 робочих днів',
    'card.view': 'Переглянути →',
    'rating.rateThis': 'Оцініть товар', 'rating.yourReview': 'Ваш відгук',
    'rating.final': 'Дякуємо за оцінку — відгук неможливо змінити після надсилання.',
    'rating.purchasedNote': 'Ви придбали цей товар — поділіться враженнями. Оцінка остаточна.',
    'rating.signInNote1': '⭐ Відгуки доступні перевіреним покупцям.',
    'rating.signInNote2': 'а після виконання замовлення ви зможете залишити оцінку тут.',
    'rating.buyNote': '⭐ Ви зможете оцінити товар після його придбання та оплати замовлення.',
    'rating.submit': 'Надіслати відгук', 'rating.saving': 'Збереження…',
    'rating.noReviews': 'Ще немає відгуків', 'rating.customerReviews': 'Відгуки покупців',
    'rating.commentPlaceholder': 'Додати коментар (необов’язково)',
    'detail.materials': 'Матеріали:', 'detail.dimensions': 'Розміри:', 'detail.weight': 'Вага:',
    'detail.care': 'Догляд:', 'detail.delivery': 'Доставка:', 'detail.deliveryValue': '📦 Безкоштовна доставка · 5-7 робочих днів',
    'detail.addToCart': 'ДОДАТИ В КОШИК', 'detail.inCart': 'У кошику',
    'filters.title': 'Фільтри', 'filters.clearAll': 'Очистити', 'filters.priceRange': 'Діапазон цін', 'filters.color': 'Колір',
    'cart.title': 'Кошик', 'cart.empty': 'Ваш кошик порожній', 'cart.items': 'Товари в кошику',
    'cart.chooseDelivery': 'Оберіть доставку', 'cart.yourDetails': 'Ваші дані', 'cart.shippingAddress': 'Адреса доставки',
    'cart.subtotal': 'Проміжна сума:', 'cart.delivery': 'Доставка:', 'cart.total': 'Разом:',
    'cart.secure': '🔒 Безпечна оплата · замовлення підтверджується лише після оплати',
    'cart.proceed': 'ПЕРЕЙТИ ДО ОПЛАТИ', 'cart.processing': 'ОБРОБКА…',
    'delivery.standard': 'Стандартна доставка', 'delivery.standardDays': '5-7 робочих днів',
    'delivery.express': 'Експрес-доставка', 'delivery.expressDays': '2-3 робочі дні',
    'delivery.overnight': 'Доставка наступного дня', 'delivery.overnightDays': 'Наступного робочого дня',
    'form.fullName': 'Повне ім’я', 'form.email': 'Електронна пошта', 'form.street': 'Вулиця та будинок',
    'form.apt': 'Квартира, офіс тощо (необов’язково)', 'form.city': 'Місто', 'form.state': 'Область',
    'form.postal': 'Поштовий індекс', 'form.country': 'Країна',
    'collections.explore': 'Перегляньте наші колекції', 'collections.subtitle': 'Прикраси, дібрані за темою та натхненням',
    'shop.noProducts': 'Товарів не знайдено', 'shop.search': 'Пошук товарів...',
    'sort.featured': 'Рекомендовані', 'sort.priceLow': 'Ціна: за зростанням', 'sort.priceHigh': 'Ціна: за спаданням', 'sort.topRated': 'Найкраще оцінені',
    'hero.eyebrow': 'Прикраси з бісеру ручної роботи', 'hero.title': 'Прикраси зі змістом',
    'hero.text': 'Кожен виріб BeeJou створюється вручну невеликими партіями з натуральних каменів, прісноводних перлів та якісного бісеру — щоб його носили, любили й передавали далі.',
    'hero.cta': 'Переглянути колекцію ↓',
    'about.title': 'Наша історія',
    'about.p1': 'BeeJou почалося за кухонним столом, намистинка за намистинкою. Те, що було тихим вечірнім хобі, переросло у невелику майстерню, присвячену прикрасам ручної роботи — ніколи не масовим.',
    'about.p2': 'Ми обираємо матеріали, які любимо: натуральний аметист і бірюзу, японський бісер Miyuki, прісноводні перли та гіпоалергенну фурнітуру. Кожен дизайн створюється обмеженою кількістю, тож виріб справді ваш.',
    'about.handmade': 'Ручна робота', 'about.handmadeText': 'Зібрано вручну невеликими партіями.',
    'about.natural': 'Натуральні матеріали', 'about.naturalText': 'Справжні камені, перли та якісна фурнітура.',
    'about.lasting': 'Довговічність', 'about.lastingText': 'Міцна конструкція, дбайливе оздоблення.',
    'contact.title': 'Зв’яжіться з нами', 'contact.lead': 'Запитання, індивідуальні замовлення чи просто привітатися — напишіть нам.',
    'contact.name': 'Ваше ім’я (необов’язково)', 'contact.email': 'Ваша пошта *', 'contact.message': 'Ваше повідомлення *',
    'contact.attach': '📎 Додати зображення', 'contact.send': 'Надіслати', 'contact.sending': 'Надсилання…',
    'contact.success': '✓ Дякуємо! Ваше повідомлення надіслано. Ми скоро зв’яжемося з вами.', 'contact.sendAnother': 'Надіслати ще',
    'contact.needFields': 'Будь ласка, вкажіть пошту та повідомлення.',
    'contact.sendingAs': 'Надсилаєте як',
    'login.subtitle': 'Увійдіть, щоб зберігати улюблене та відстежувати замовлення',
    'login.demoNote': 'Демо-режим — Google не налаштовано.', 'login.demoBtn': 'Продовжити як демо-користувач',
    'account.title': 'Мій кабінет', 'account.logout': 'Вийти', 'account.liked': 'Улюблене', 'account.orders': 'Замовлення',
    'account.noLikes': 'Ще немає улюблених товарів.', 'account.noOrders': 'Ще немає замовлень.',
    'account.rateHint': '★ Натисніть на зірки, щоб оцінити покупки', 'account.yourRating': 'ваша оцінка',
    'account.address': 'Адреса', 'account.addressIntro': 'Збережіть адресу доставки, щоб прискорити оформлення.', 'account.saveAddress': 'Зберегти адресу', 'account.addressSaved': 'Збережено',
    'account.rateIt': 'оцінити', 'account.submit': 'Надіслати', 'account.saving': 'Збереження…', 'account.item': 'товар(ів)',
    'footer': 'BeeeJou © 2024 | Зроблено з ❤️ | ', 'footer.etsy': 'Відвідати магазин Etsy',
    'checkout.needEmail': 'Введіть свою пошту, щоб продовжити.',
    'checkout.needAddress': 'Заповніть адресу доставки (вулиця, місто, індекс, країна).',
    'checkout.thankYou': 'Дякуємо! Оплату отримано. Ваше замовлення {ref} підтверджено.',
    'checkout.payNow': 'Сплатити зараз ${amount} USD? (демо-оплата — замовлення {ref})',
    'off': 'ЗНИЖКА',
    'cat.All': 'Усі', 'cat.Bracelets': 'Браслети', 'cat.Earrings': 'Сережки',
    'cat.Necklaces': 'Намиста', 'cat.Sets': 'Комплекти', 'cat.Clearance': 'Розпродаж',
    'cat.Rings': 'Каблучки', 'cat.Anklets': 'Браслети на ногу',
    'coll.Gemstone Journey': 'Подорож самоцвітів', 'coll.Luminous Elegance': 'Сяйлива елегантність',
    'coll.Metallic Harmony': 'Металева гармонія', 'coll.Prismatic Dreams': 'Призматичні мрії',
    'coll.Summer Radiance': 'Літнє сяйво', 'coll.Timeless Treasures': 'Позачасові скарби',
    'collDesc.Gemstone Journey': 'Відкрийте природну красу ретельно дібраних намистин із самоцвітів у чарівних відтінках',
    'collDesc.Luminous Elegance': 'Сяйте блиском перлів, кристалів та світлих дизайнів',
    'collDesc.Metallic Harmony': 'Сучасна розкіш через поєднання металів і сучасні оздоблення',
    'collDesc.Prismatic Dreams': 'Святкуйте колір і творчість яскравими багатобарвними виробами',
    'collDesc.Summer Radiance': 'Легкі, яскраві та ідеальні для теплого сезону',
    'collDesc.Timeless Treasures': 'Вироби у вінтажному стилі з характером та історією',
    'cookie.text': 'Ми використовуємо локальне сховище, щоб зберігати ваш кошик, улюблене та мову, а також файл входу, якщо ви авторизуєтесь. Ми не використовуємо файли для відстеження чи реклами.',
    'cookie.accept': 'Зрозуміло',
    'cookie.learn': 'Конфіденційність',
    'consent.marketing': 'Я хочу отримувати періодичні пропозиції та новини електронною поштою. Ви можете відписатися будь-коли.',
  },
};

const LangContext = createContext({ lang: 'en', setLang: () => {} });

// Translate a key for the current language, with {placeholder} interpolation
function translate(lang, key, vars) {
  let s = (TRANSLATIONS[lang] && TRANSLATIONS[lang][key]) || TRANSLATIONS.en[key] || key;
  if (vars) for (const k in vars) s = s.replace(`{${k}}`, vars[k]);
  return s;
}

// Hook: returns the t() function bound to the current language
function useT() {
  const { lang } = useContext(LangContext);
  return (key, vars) => translate(lang, key, vars);
}

// Header language switcher
function LanguageSwitcher() {
  const { lang, setLang } = useContext(LangContext);
  return (
    <div className="lang-switcher">
      {LANGUAGES.map(l => (
        <button
          key={l.code}
          className={`lang-btn ${lang === l.code ? 'active' : ''}`}
          onClick={() => setLang(l.code)}
          title={l.name}
        >{l.label}</button>
      ))}
    </div>
  );
}

// Cookie / local-storage consent banner.
// We only use functional storage (cart, favorites, language, sign-in token) — no
// tracking/ad cookies — so a simple "acknowledge" banner satisfies ePrivacy/GDPR.
const COOKIE_CONSENT_KEY = 'beejou_cookie_ack';
function CookieConsent() {
  const t = useT();
  const [show, setShow] = useState(false);

  useEffect(() => {
    // Show only once, after the rest of the page has settled
    if (!localStorage.getItem(COOKIE_CONSENT_KEY)) {
      const id = setTimeout(() => setShow(true), 800);
      return () => clearTimeout(id);
    }
  }, []);

  const accept = () => {
    try { localStorage.setItem(COOKIE_CONSENT_KEY, new Date().toISOString()); } catch {}
    setShow(false);
  };

  if (!show) return null;
  return (
    <div className="cookie-banner" role="dialog" aria-live="polite">
      <p className="cookie-text">
        {t('cookie.text')}{' '}
        <a href="#contact" className="cookie-learn" onClick={() => setShow(false)}>{t('cookie.learn')}</a>
      </p>
      <button className="cookie-accept" onClick={accept}>{t('cookie.accept')}</button>
    </div>
  );
}

// Authenticated fetch helper — attaches the shopper's session token if present
function userFetch(url, opts = {}) {
  const token = localStorage.getItem(USER_TOKEN_KEY);
  const headers = { 'Content-Type': 'application/json', ...(opts.headers || {}) };
  if (token) headers['X-User-Token'] = token;
  return fetch(url, { ...opts, headers });
}

// Google Sign-In button — renders the official GIS button into a div
function GoogleSignInButton({ clientId, onCredential }) {
  const ref = useRef(null);
  useEffect(() => {
    if (!clientId || !window.google || !ref.current) return;
    window.google.accounts.id.initialize({
      client_id: clientId,
      callback: (resp) => onCredential(resp.credential),
    });
    window.google.accounts.id.renderButton(ref.current, { theme: 'outline', size: 'large', shape: 'pill' });
  }, [clientId]);
  return <div ref={ref} />;
}

// Header Component with Navigation
function Header({ cart, onCartClick, user, onAccountClick, onLoginClick, onNavigate }) {
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
  const t = useT();

  const go = (section) => (e) => {
    e.preventDefault();
    setMobileMenuOpen(false);
    onNavigate(section);
  };

  return (
    <header className="header-pro">
      <a href="#home" className="header-banner">
        <img src="/images/beejou baner.png" alt="BeeeJou Banner" className="banner-image" />
      </a>

      <div className="header-sticky">
      <div className="header-top">
        <div className="container-fluid">
          <div className="header-content">
            <div className="logo-section">
              <h1 className="logo">BeeJou</h1>
              <p className="logo-sub">{t('tagline')}</p>
            </div>

            <div className="menu-toggle" onClick={() => setMobileMenuOpen(!mobileMenuOpen)}>
              ☰
            </div>

            <nav className={`nav-menu ${mobileMenuOpen ? 'open' : ''}`}>
              <a href="#home" className="nav-link" onClick={go('home')}>{t('nav.home')}</a>
              <a href="#collections" className="nav-link" onClick={go('collections')}>{t('nav.collections')}</a>
              <a href="#about" className="nav-link" onClick={go('about')}>{t('nav.about')}</a>
              <a href="#contact" className="nav-link" onClick={go('contact')}>{t('nav.contact')}</a>
              <div className="nav-lang-mobile"><LanguageSwitcher /></div>
            </nav>

            <div className="cart-section">
              <span className="lang-switcher-desktop"><LanguageSwitcher /></span>
              {user ? (
                <button className="account-btn" onClick={onAccountClick} title={t('nav.account')}>
                  {user.picture
                    ? <img src={user.picture} alt="" className="account-avatar" referrerPolicy="no-referrer" />
                    : <span className="account-avatar fallback">{(user.name || 'U')[0]}</span>}
                  <span className="account-name">{(user.name || '').split(' ')[0] || t('nav.account')}</span>
                </button>
              ) : (
                <button className="login-btn" onClick={onLoginClick}>{t('nav.signIn')}</button>
              )}
              <button className="cart-btn" onClick={onCartClick}>
                🛒 {t('nav.cart')}
                {cart.length > 0 && <span className="cart-count">{cart.length}</span>}
              </button>
            </div>
          </div>
        </div>
      </div>

      </div>
    </header>
  );
}

// Image Gallery Component
function ImageGallery({ images, productName }) {
  const [currentIndex, setCurrentIndex] = useState(0);

  const goToSlide = (index) => {
    setCurrentIndex(index % images.length);
  };

  const nextSlide = () => {
    setCurrentIndex((prev) => (prev + 1) % images.length);
  };

  return (
    <div className="image-gallery">
      <div className="main-image">
        <img src={images[currentIndex]} alt={productName} />
        {images.length > 1 && (
          <>
            <button className="gallery-nav prev" onClick={() => goToSlide(currentIndex - 1)}>‹</button>
            <button className="gallery-nav next" onClick={nextSlide}>›</button>
          </>
        )}
      </div>

      {images.length > 1 && (
        <div className="thumbnail-row">
          {images.map((img, idx) => (
            <button
              key={idx}
              className={`thumbnail ${idx === currentIndex ? 'active' : ''}`}
              onClick={() => goToSlide(idx)}
            >
              <img src={img} alt={`${productName} ${idx + 1}`} />
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

// Pick a product field in the active language, falling back to the default
function localizedField(product, field, lang) {
  if (lang && lang !== 'en') {
    const v = product[`${field}_${lang}`];
    if (v) return v;
  }
  return product[field];
}

// Product Card Component
function ProductCard({ product, onSelect, onLike, isFavorite }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  const images = product.images || [product.image];
  const name = localizedField(product, 'name', lang);
  const description = localizedField(product, 'description', lang);

  return (
    <div className="product-card-pro" onClick={() => onSelect(product)}>
      <div className="product-image-section">
        <ImageGallery images={images} productName={name} />

        {product.salePercent && (
          <div className="sale-badge">{product.salePercent}% {t('off')}</div>
        )}

        <button
          className={`like-btn ${isFavorite ? 'liked' : ''}`}
          onClick={(e) => {
            e.stopPropagation();
            onLike(product.id);
          }}
        >
          ♥
        </button>
      </div>

      <div className="product-info-section">
        <div className="category-tag">{product.category}</div>
        <h3 className="product-title">{name}</h3>
        <p className="product-desc">{description}</p>

        <div className="rating-row">
          {product.reviews > 0 ? (
            <>
              <StarDisplay value={product.rating} />
              <span className="rating">{product.rating}</span>
              <span className="reviews">({product.reviews})</span>
            </>
          ) : (
            <span className="reviews no-reviews">{t('card.new')}</span>
          )}
          {product.color && (
            <span className="color-chip" title={product.color}>
              <span className="color-chip-dot" style={{ background: COLOR_SWATCHES[product.color] || product.color }} />
              {product.color}
            </span>
          )}
        </div>

        <div className="delivery-info-card">
          <span className="delivery-badge">{t('card.freeDelivery')}</span>
          <span className="delivery-time">{t('card.deliveryTime')}</span>
        </div>

        <div className="price-section">
          <div className={`price ${product.salePrice ? 'on-sale' : ''}`}>
            <span className="current-price">${(product.salePrice || product.price).toFixed(2)}</span>
            {product.salePrice && <span className="original-price">${product.price.toFixed(2)}</span>}
          </div>
          <button className="quick-btn" onClick={(e) => {
            e.stopPropagation();
            onSelect(product);
          }}>
            {t('card.view')}
          </button>
        </div>
      </div>
    </div>
  );
}

// Star display (read-only) — supports fractional fill for averages
function StarDisplay({ value }) {
  const v = Number(value) || 0;
  return (
    <span className="stars" aria-label={`${v} out of 5`}>
      {[1, 2, 3, 4, 5].map(n => (
        <span key={n} className={`star ${v >= n ? 'full' : v >= n - 0.5 ? 'half' : 'empty'}`}>★</span>
      ))}
    </span>
  );
}

// Interactive star picker for submitting a rating
function StarInput({ value, onChange }) {
  const [hover, setHover] = useState(0);
  return (
    <span className="stars-input">
      {[1, 2, 3, 4, 5].map(n => (
        <button
          type="button"
          key={n}
          className={`star ${(hover || value) >= n ? 'full' : 'empty'}`}
          onMouseEnter={() => setHover(n)}
          onMouseLeave={() => setHover(0)}
          onClick={() => onChange(n)}
        >★</button>
      ))}
    </span>
  );
}

// Rating section inside the product modal — gated on a paid order
function RatingPanel({ product, onRated, user, onLoginClick }) {
  const t = useT();
  const existing = product.myRating;
  const [stars, setStars] = useState(existing ? existing.stars : 0);
  const [comment, setComment] = useState(existing ? existing.comment || '' : '');
  const [saving, setSaving] = useState(false);
  const [done, setDone] = useState(false);
  const [error, setError] = useState('');

  const submit = async () => {
    if (!stars) { setError('Please pick a star rating.'); return; }
    setSaving(true); setError('');
    try {
      const res = await userFetch(`/api/furniture/${product.id}/rate`, {
        method: 'POST',
        body: JSON.stringify({ stars, comment }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Could not submit rating');
      setDone(true);
      onRated(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setSaving(false);
    }
  };

  // Show context-aware guidance when the user can't rate yet, so it's never a mystery
  if (!product.canRate) {
    return (
      <div className="rating-panel rating-locked">
        <h4>{t('rating.rateThis')}</h4>
        {!user ? (
          <p className="rating-panel-note">
            {t('rating.signInNote1')}{' '}
            <button className="link-like" onClick={onLoginClick}>{t('nav.signIn')}</button>{' '}
            {t('rating.signInNote2')}
          </p>
        ) : (
          <p className="rating-panel-note">
            {t('rating.buyNote')}
          </p>
        )}
      </div>
    );
  }

  // Once submitted, the review is final and shown read-only (no editing)
  if (existing || done) {
    const r = existing || { stars, comment };
    return (
      <div className="rating-panel">
        <h4>{t('rating.yourReview')}</h4>
        <StarDisplay value={r.stars} />
        {r.comment && <p className="review-comment">“{r.comment}”</p>}
        <p className="rating-panel-note">{t('rating.final')}</p>
      </div>
    );
  }

  return (
    <div className="rating-panel">
      <h4>{t('rating.rateThis')}</h4>
      <p className="rating-panel-note">{t('rating.purchasedNote')}</p>
      <StarInput value={stars} onChange={setStars} />
      <textarea
        rows="2"
        placeholder={t('rating.commentPlaceholder')}
        value={comment}
        onChange={(e) => setComment(e.target.value)}
      />
      {error && <div className="checkout-error">{error}</div>}
      <button className="rating-submit" onClick={submit} disabled={saving}>
        {saving ? t('rating.saving') : t('rating.submit')}
      </button>
    </div>
  );
}

// Product Detail Modal
function ProductDetailModal({ product: initialProduct, onClose, onAddToCart, cart, user, onLoginClick }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  const [product, setProduct] = useState(initialProduct);
  const images = product.images || [product.image];
  const cartItem = cart.find(item => item.id === product.id);
  const quantity = cartItem ? cartItem.quantity : 0;
  const name = localizedField(product, 'name', lang);
  const fullDescription = localizedField(product, 'fullDescription', lang) || localizedField(product, 'description', lang);

  // Fetch full product (rating context: canRate, myRating, reviewsList)
  useEffect(() => {
    userFetch(`/api/furniture/${initialProduct.id}`)
      .then(r => r.json())
      .then(setProduct)
      .catch(() => {});
  }, [initialProduct.id]);

  const handleRated = () => {
    // Refetch so the reviews list + averages reflect the new rating immediately
    userFetch(`/api/furniture/${initialProduct.id}`).then(r => r.json()).then(setProduct).catch(() => {});
  };

  const handleQuantityChange = (newQty) => {
    if (newQty > 0) {
      onAddToCart(product, newQty - quantity);
    } else {
      onClose();
    }
  };

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        <button className="modal-close" onClick={onClose}>✕</button>

        <div className="modal-body">
          <div className="modal-images">
            <ImageGallery images={images} productName={name} />
          </div>

          <div className="modal-details">
            <div className="modal-category">{product.category}</div>
            <h2>{name}</h2>

            <div className="rating-details">
              {product.reviews > 0 ? (
                <>
                  <StarDisplay value={product.rating} />
                  <span className="reviews">{product.rating} · {product.reviews} ★</span>
                </>
              ) : (
                <span className="reviews no-reviews">{t('rating.noReviews')}</span>
              )}
            </div>

            <p className="description-full">{fullDescription}</p>

            <div className="specs-grid">
              <div className="spec">
                <strong>{t('detail.materials')}</strong>
                <ul>
                  {product.materials.map((m, i) => <li key={i}>{m}</li>)}
                </ul>
              </div>
              <div className="spec">
                <strong>{t('detail.dimensions')}</strong>
                <p>{product.dimensions}</p>
              </div>
              <div className="spec">
                <strong>{t('detail.weight')}</strong>
                <p>{product.weight}</p>
              </div>
              <div className="spec">
                <strong>{t('detail.care')}</strong>
                <p>{product.care}</p>
              </div>
              <div className="spec">
                <strong>{t('detail.delivery')}</strong>
                <p>{t('detail.deliveryValue')}</p>
              </div>
            </div>

            <div className={`price-large ${product.salePrice ? 'on-sale' : ''}`}>
              <span className="amount">${(product.salePrice || product.price).toFixed(2)}</span>
              {product.salePrice && (
                <span className="original">${product.price.toFixed(2)}</span>
              )}
            </div>

            <div className="action-section">
              <div className="quantity-control">
                <button onClick={() => handleQuantityChange(quantity - 1)}>−</button>
                <span>{quantity}</span>
                <button onClick={() => handleQuantityChange(quantity + 1)}>+</button>
              </div>
              <button className="add-to-cart-btn" onClick={() => {
                if (quantity === 0) onAddToCart(product, 1);
              }}>
                {quantity > 0 ? `${t('detail.inCart')} (${quantity})` : t('detail.addToCart')}
              </button>
            </div>

            <RatingPanel product={product} onRated={handleRated} user={user} onLoginClick={onLoginClick} />

            {product.reviewsList && product.reviewsList.length > 0 && (
              <div className="reviews-list">
                <h4>{t('rating.customerReviews')}</h4>
                {product.reviewsList.map((r, i) => (
                  <div className="review-item" key={i}>
                    <StarDisplay value={r.stars} />
                    {r.comment && <p className="review-comment">{r.comment}</p>}
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

// Delivery Options (name/days are translation keys; `name` kept for the server)
const DELIVERY_OPTIONS = [
  { id: 'standard', name: 'Standard Delivery', nameKey: 'delivery.standard', daysKey: 'delivery.standardDays', price: 0, icon: '📦' },
  { id: 'express', name: 'Express Delivery', nameKey: 'delivery.express', daysKey: 'delivery.expressDays', price: 9.99, icon: '🚚' },
  { id: 'overnight', name: 'Overnight Delivery', nameKey: 'delivery.overnight', daysKey: 'delivery.overnightDays', price: 24.99, icon: '✈️' }
];

// Color swatch mapping
const COLOR_SWATCHES = {
  Purple: '#9b59b6',
  Blue: '#3498db',
  White: '#f5f5f5',
  Gold: '#d4af37',
  Green: '#27ae60',
  Silver: '#bdc3c7',
  Pink: '#e91e8c',
  Multicolor: 'linear-gradient(135deg, #e74c3c, #f1c40f, #2ecc71, #3498db, #9b59b6)',
  Bronze: '#cd7f32'
};

// Filter Sidebar Component
function FilterSidebar({ priceBounds, priceRange, onPriceChange, availableColors, selectedColors, onToggleColor, onClear }) {
  const t = useT();
  const hasActiveFilters = selectedColors.length > 0 ||
    priceRange.min !== priceBounds.min || priceRange.max !== priceBounds.max;

  return (
    <aside className="filter-sidebar">
      <div className="filter-header">
        <h3>{t('filters.title')}</h3>
        {hasActiveFilters && (
          <button className="clear-filters" onClick={onClear}>{t('filters.clearAll')}</button>
        )}
      </div>

      <div className="filter-group">
        <h4 className="filter-title">{t('filters.priceRange')}</h4>
        <div className="price-values">
          <span>${priceRange.min}</span>
          <span>${priceRange.max}</span>
        </div>
        <div className="price-sliders">
          <div className="price-track">
            <div
              className="price-track-fill"
              style={{
                left: `${((priceRange.min - priceBounds.min) / Math.max(1, priceBounds.max - priceBounds.min)) * 100}%`,
                right: `${100 - ((priceRange.max - priceBounds.min) / Math.max(1, priceBounds.max - priceBounds.min)) * 100}%`,
              }}
            />
          </div>
          <input
            type="range"
            min={priceBounds.min}
            max={priceBounds.max}
            value={priceRange.min}
            onChange={(e) => {
              const val = Math.min(Number(e.target.value), priceRange.max - 1);
              onPriceChange({ ...priceRange, min: val });
            }}
            className="price-slider min-slider"
          />
          <input
            type="range"
            min={priceBounds.min}
            max={priceBounds.max}
            value={priceRange.max}
            onChange={(e) => {
              const val = Math.max(Number(e.target.value), priceRange.min + 1);
              onPriceChange({ ...priceRange, max: val });
            }}
            className="price-slider max-slider"
          />
        </div>
        <div className="price-inputs">
          <input
            type="number"
            value={priceRange.min}
            min={priceBounds.min}
            max={priceRange.max}
            onChange={(e) => onPriceChange({ ...priceRange, min: Number(e.target.value) })}
          />
          <span className="dash">—</span>
          <input
            type="number"
            value={priceRange.max}
            min={priceRange.min}
            max={priceBounds.max}
            onChange={(e) => onPriceChange({ ...priceRange, max: Number(e.target.value) })}
          />
        </div>
      </div>

      <div className="filter-group">
        <h4 className="filter-title">{t('filters.color')}</h4>
        <div className="color-swatches">
          {availableColors.map(color => (
            <button
              key={color}
              className={`color-swatch ${selectedColors.includes(color) ? 'selected' : ''}`}
              onClick={() => onToggleColor(color)}
              title={color}
            >
              <span
                className="swatch-dot"
                style={{ background: COLOR_SWATCHES[color] || color }}
              />
              <span className="swatch-label">{color}</span>
            </button>
          ))}
        </div>
      </div>
    </aside>
  );
}

// Shopping Cart
const BLANK_ADDRESS = { line1: '', line2: '', city: '', state: '', postal: '', country: '' };

// Prefill the shipping address from the user's saved address, or a guest's
// last-used address kept in localStorage.
function initialAddress(user) {
  if (user && user.shippingAddress) return { ...BLANK_ADDRESS, ...user.shippingAddress };
  try {
    const saved = JSON.parse(localStorage.getItem('beejou-address') || 'null');
    if (saved) return { ...BLANK_ADDRESS, ...saved };
  } catch {}
  return { ...BLANK_ADDRESS };
}

function ShoppingCart({ cart, onClose, onUpdateCart, onOrderComplete, user }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  const [selectedDelivery, setSelectedDelivery] = useState('standard');
  const [name, setName] = useState(user ? user.name || '' : '');
  const [email, setEmail] = useState(user ? user.email || '' : '');
  const [ship, setShip] = useState(() => initialAddress(user));
  const [marketingConsent, setMarketingConsent] = useState(false); // GDPR: opt-in, off by default
  const [processing, setProcessing] = useState(false);
  const [error, setError] = useState('');

  const setShipField = (k) => (e) => setShip(s => ({ ...s, [k]: e.target.value }));

  const subtotal = cart.reduce((sum, item) => sum + ((item.salePrice || item.price) * item.quantity), 0);
  const deliveryOption = DELIVERY_OPTIONS.find(opt => opt.id === selectedDelivery);
  const total = subtotal + (deliveryOption?.price || 0);

  const handleCheckout = async () => {
    setError('');
    if (!email) { setError(t('checkout.needEmail')); return; }
    if (!ship.line1 || !ship.city || !ship.postal || !ship.country) {
      setError(t('checkout.needAddress'));
      return;
    }
    setProcessing(true);
    try {
      const res = await userFetch('/api/checkout', {
        method: 'POST',
        body: JSON.stringify({
          items: cart.map(i => ({ id: i.id, quantity: i.quantity })),
          customerName: name,
          customerEmail: email,
          deliveryMethod: deliveryOption?.name,
          deliveryPrice: deliveryOption?.price || 0,
          shippingAddress: ship,
          marketingConsent,
        }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Checkout failed');

      // Remember the address locally so it prefills next time (guests too)
      try { localStorage.setItem('beejou-address', JSON.stringify(ship)); } catch {}

      // Real payment: hand off to Stripe Checkout. Order is saved as paid only
      // after Stripe confirms (handled on return to the store).
      if (data.mode === 'stripe' && data.url) {
        window.location.href = data.url;
        return;
      }

      // Mock mode (no Stripe key): simulate a completed payment after confirmation.
      const ok = window.confirm(t('checkout.payNow', { amount: total.toFixed(2), ref: data.reference }));
      if (!ok) { setProcessing(false); return; }
      const confirm = await fetch('/api/checkout/confirm', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ reference: data.reference }),
      });
      const cdata = await confirm.json();
      if (!confirm.ok) throw new Error(cdata.error || 'Payment failed');
      onOrderComplete(data.reference);
    } catch (err) {
      setError(err.message);
      setProcessing(false);
    }
  };

  return (
    <div className="cart-panel" onClick={onClose}>
      <div className="cart-content" onClick={(e) => e.stopPropagation()}>
        <div className="cart-header">
          <h2>{t('cart.title')}</h2>
          <button onClick={onClose}>✕</button>
        </div>

        {cart.length === 0 ? (
          <div className="empty-cart">{t('cart.empty')}</div>
        ) : (
          <div className="cart-main">
            {/* Items Section */}
            <div className="cart-items-section">
              <div className="section-label">{t('cart.items')}</div>
              <div className="cart-items">
                {cart.map(item => (
                  <div key={item.id} className="cart-item">
                    <img src={item.image} alt={localizedField(item, 'name', lang)} />
                    <div className="item-info">
                      <h4>{localizedField(item, 'name', lang)}</h4>
                      <p>${(item.salePrice || item.price).toFixed(2)} × {item.quantity}</p>
                    </div>
                    <div className="item-actions">
                      <button onClick={() => onUpdateCart(item.id, item.quantity - 1)}>−</button>
                      <span>{item.quantity}</span>
                      <button onClick={() => onUpdateCart(item.id, item.quantity + 1)}>+</button>
                    </div>
                    <div className="item-total">
                      ${((item.salePrice || item.price) * item.quantity).toFixed(2)}
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Delivery & Summary Section */}
            <div className="checkout-section">
              <div className="delivery-section">
                <div className="section-label">{t('cart.chooseDelivery')}</div>
                <div className="delivery-options">
                  {DELIVERY_OPTIONS.map(option => (
                    <label key={option.id} className={`delivery-option ${selectedDelivery === option.id ? 'selected' : ''}`}>
                      <input
                        type="radio"
                        name="delivery"
                        value={option.id}
                        checked={selectedDelivery === option.id}
                        onChange={(e) => setSelectedDelivery(e.target.value)}
                      />
                      <div className="delivery-content">
                        <div className="delivery-header">
                          <span className="delivery-icon">{option.icon}</span>
                          <span className="delivery-name">{t(option.nameKey)}</span>
                          <span className="delivery-price">${option.price.toFixed(2)}</span>
                        </div>
                        <div className="delivery-timing">⏱️ {t(option.daysKey)}</div>
                      </div>
                    </label>
                  ))}
                </div>
              </div>

              <div className="cart-footer">
                <div className="section-label">{t('cart.yourDetails')}</div>
                <div className="checkout-fields">
                  <input
                    type="text"
                    placeholder={t('form.fullName')}
                    value={name}
                    onChange={(e) => setName(e.target.value)}
                    className="checkout-input"
                  />
                  <input
                    type="email"
                    placeholder={t('form.email')}
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    className="checkout-input"
                    required
                  />
                </div>
                <div className="section-label">{t('cart.shippingAddress')}</div>
                <div className="checkout-fields">
                  <input type="text" placeholder={t('form.street')} value={ship.line1} onChange={setShipField('line1')} className="checkout-input" />
                  <input type="text" placeholder={t('form.apt')} value={ship.line2} onChange={setShipField('line2')} className="checkout-input" />
                  <div className="checkout-row">
                    <input type="text" placeholder={t('form.city')} value={ship.city} onChange={setShipField('city')} className="checkout-input" />
                    <input type="text" placeholder={t('form.state')} value={ship.state} onChange={setShipField('state')} className="checkout-input" />
                  </div>
                  <div className="checkout-row">
                    <input type="text" placeholder={t('form.postal')} value={ship.postal} onChange={setShipField('postal')} className="checkout-input" />
                    <input type="text" placeholder={t('form.country')} value={ship.country} onChange={setShipField('country')} className="checkout-input" />
                  </div>
                </div>
                <div className="cart-summary">
                  <div className="summary-row">
                    <span>{t('cart.subtotal')}</span>
                    <span>${subtotal.toFixed(2)}</span>
                  </div>
                  <div className="summary-row">
                    <span>{t('cart.delivery')}</span>
                    <span>${(deliveryOption?.price || 0).toFixed(2)}</span>
                  </div>
                </div>
                <div className="cart-total">
                  <strong>{t('cart.total')}</strong>
                  <strong>${total.toFixed(2)}</strong>
                </div>
                <label className="marketing-consent">
                  <input
                    type="checkbox"
                    checked={marketingConsent}
                    onChange={(e) => setMarketingConsent(e.target.checked)}
                  />
                  <span>{t('consent.marketing')}</span>
                </label>
                {error && <div className="checkout-error">{error}</div>}
                <button className="checkout-btn" onClick={handleCheckout} disabled={processing}>
                  {processing ? t('cart.processing') : t('cart.proceed')}
                </button>
                <p className="checkout-note">{t('cart.secure')}</p>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// Featured Collections Component
function FeaturedCollections({ collections, onSelectCollection, selectedCollection }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  if (collections.length === 0) return null;

  return (
    <section className="featured-collections">
      <div className="section-header">
        <h2>{t('collections.explore')}</h2>
        <p>{t('collections.subtitle')}</p>
      </div>
      <div className="collections-grid">
        {collections.map(collection => (
          <div
            key={collection.name}
            className={`collection-card ${selectedCollection === collection.name ? 'active' : ''}`}
            onClick={() => onSelectCollection(collection.name)}
          >
            <div className="collection-preview">
              {collection.products.length > 0 && (
                <img src={collection.products[0].image} alt={collection.name} />
              )}
            </div>
            <div className="collection-info">
              <h3>{collectionName(collection.name, lang)}</h3>
              <p className="collection-desc">{collectionDesc(collection.name, lang)}</p>
              <span className="collection-count">{collection.products.length} {t('account.item')}</span>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

// Translate a collection's display name; unknown collections pass through
function collectionName(name, lang) {
  const dict = TRANSLATIONS[lang] || {};
  return dict[`coll.${name}`] || TRANSLATIONS.en[`coll.${name}`] || name;
}
// Translate a collection's tagline; falls back to English then a generic line
function collectionDesc(name, lang) {
  const dict = TRANSLATIONS[lang] || {};
  return dict[`collDesc.${name}`] || TRANSLATIONS.en[`collDesc.${name}`] || '';
}

// Product Grid
function ProductGrid({ products, onSelectProduct, favorites, onToggleFavorite, onAddToCart }) {
  const t = useT();
  if (products.length === 0) {
    return <div className="no-results">{t('shop.noProducts')}</div>;
  }

  return (
    <div className="products-grid">
      {products.map(product => (
        <ProductCard
          key={product.id}
          product={product}
          onSelect={onSelectProduct}
          onLike={onToggleFavorite}
          isFavorite={favorites.includes(product.id)}
        />
      ))}
    </div>
  );
}

// Illustration (emoji) for each category — falls back to a gem for new ones
const CATEGORY_ICONS = {
  All: '✦',
  Bracelets: '📿',
  Earrings: '👂',
  Necklaces: '💎',
  Sets: '🎁',
  Clearance: '🏷️',
  Rings: '💍',
  Anklets: '🦶',
};
const categoryIcon = (cat) => CATEGORY_ICONS[cat] || '💠';

// Translate well-known category names; unknown (custom) categories pass through
function categoryLabel(cat, lang) {
  const key = `cat.${cat}`;
  const dict = TRANSLATIONS[lang] || {};
  return dict[key] || (TRANSLATIONS.en[key]) || cat;
}

// Home hero section — with centered category selector underneath the title
function HeroSection({ onShopClick, allCategories, selectedCategory, onCategoryChange }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  return (
    <section id="home" className="hero-section">
      <div className="hero-inner">
        <p className="hero-eyebrow">{t('hero.eyebrow')}</p>
        <h2 className="hero-title">{t('hero.title')}</h2>
        <p className="hero-text">{t('hero.text')}</p>

        <div className="hero-categories">
          {allCategories.map(cat => (
            <button
              key={cat}
              className={`hero-cat ${selectedCategory === cat ? 'active' : ''}`}
              onClick={() => onCategoryChange(cat)}
            >
              <span className="hero-cat-icon">{categoryIcon(cat)}</span>
              <span className="hero-cat-label">{categoryLabel(cat, lang)}</span>
            </button>
          ))}
        </div>

        <button className="hero-cta" onClick={onShopClick}>{t('hero.cta')}</button>
      </div>
    </section>
  );
}

// About section
function AboutSection() {
  const t = useT();
  return (
    <section id="about" className="about-section">
      <div className="about-inner">
        <h2 className="section-title">{t('about.title')}</h2>
        <p>{t('about.p1')}</p>
        <p>{t('about.p2')}</p>
        <div className="about-values">
          <div className="value"><span className="value-icon">✶</span><h4>{t('about.handmade')}</h4><p>{t('about.handmadeText')}</p></div>
          <div className="value"><span className="value-icon">❀</span><h4>{t('about.natural')}</h4><p>{t('about.naturalText')}</p></div>
          <div className="value"><span className="value-icon">♺</span><h4>{t('about.lasting')}</h4><p>{t('about.lastingText')}</p></div>
        </div>
      </div>
    </section>
  );
}

// Contact section with a message form (email, message, optional image)
function ContactSection({ user }) {
  const t = useT();
  // Logged-in shoppers don't re-type their email — we take it from their account
  const [form, setForm] = useState({ name: user ? user.name || '' : '', email: user ? user.email || '' : '', body: '' });
  const [image, setImage] = useState(null);       // data URL preview
  const [imageName, setImageName] = useState('');
  const [status, setStatus] = useState('');        // '', 'sending', 'sent', 'error'
  const [error, setError] = useState('');

  const set = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  // Keep the email synced to the account if the user logs in/out while viewing
  useEffect(() => {
    if (user) setForm(f => ({ ...f, email: user.email || f.email, name: f.name || user.name || '' }));
  }, [user]);

  const onPickImage = (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = '';
    if (!file) return;
    const r = new FileReader();
    r.onload = () => { setImage(r.result); setImageName(file.name); };
    r.readAsDataURL(file);
  };

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    if (!form.email || !form.body) { setError(t('contact.needFields')); return; }
    setStatus('sending');
    try {
      const res = await fetch('/api/contact', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ...form, image }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Could not send message');
      setStatus('sent');
      setForm({ name: '', email: '', body: '' }); setImage(null); setImageName('');
    } catch (err) {
      setStatus('error'); setError(err.message);
    }
  };

  return (
    <section id="contact" className="contact-section">
      <div className="contact-inner">
        <h2 className="section-title">{t('contact.title')}</h2>
        <p className="contact-lead">{t('contact.lead')}</p>
        {status === 'sent' ? (
          <div className="contact-success">
            {t('contact.success')}
            <button className="link-like" onClick={() => setStatus('')}>{t('contact.sendAnother')}</button>
          </div>
        ) : (
          <form className="contact-form" onSubmit={submit}>
            <div className="contact-row">
              <input type="text" placeholder={t('contact.name')} value={form.name} onChange={set('name')} />
              {user ? (
                <div className="contact-as">{t('contact.sendingAs')} <strong>{user.email}</strong></div>
              ) : (
                <input type="email" placeholder={t('contact.email')} value={form.email} onChange={set('email')} required />
              )}
            </div>
            <textarea rows="5" placeholder={t('contact.message')} value={form.body} onChange={set('body')} required />
            <div className="contact-upload">
              <label className="contact-file-btn">
                <input type="file" accept="image/*,.heic,.heif" onChange={onPickImage} hidden />
                {t('contact.attach')}
              </label>
              {image && (
                <div className="contact-img-preview">
                  <img src={image} alt="attachment" />
                  <span>{imageName}</span>
                  <button type="button" onClick={() => { setImage(null); setImageName(''); }}>✕</button>
                </div>
              )}
            </div>
            {error && <div className="checkout-error">{error}</div>}
            <button type="submit" className="contact-submit" disabled={status === 'sending'}>
              {status === 'sending' ? t('contact.sending') : t('contact.send')}
            </button>
          </form>
        )}
      </div>
    </section>
  );
}

// Login modal — Google sign-in
function LoginModal({ authConfig, onCredential, onClose }) {
  const t = useT();
  return (
    <div className="auth-overlay" onClick={onClose}>
      <div className="auth-modal" onClick={(e) => e.stopPropagation()}>
        <button className="auth-close" onClick={onClose}>✕</button>
        <h2 className="logo">BeeJou</h2>
        <p className="auth-sub">{t('login.subtitle')}</p>
        {authConfig && authConfig.enabled ? (
          <div className="gsi-wrap">
            <GoogleSignInButton clientId={authConfig.googleClientId} onCredential={onCredential} />
          </div>
        ) : (
          <div className="gsi-wrap">
            <p className="auth-note">{t('login.demoNote')}</p>
            <button className="btn-google-mock" onClick={() => {
              const mock = btoa(JSON.stringify({
                sub: 'mock-jane', email: 'jane@example.com', name: 'Jane Shopper',
              }));
              onCredential(mock);
            }}>{t('login.demoBtn')}</button>
          </div>
        )}
      </div>
    </div>
  );
}

// A single ordered item in the cabinet, with an inline rating control.
// Only paid orders allow rating, and a rating is final once submitted.
function CabinetRateRow({ item, canRate }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  const [existing, setExisting] = useState(null);   // { stars, comment } if already rated
  const [pick, setPick] = useState(0);
  const [comment, setComment] = useState('');
  const [saving, setSaving] = useState(false);
  const [loading, setLoading] = useState(canRate);

  // Load the user's existing rating for this product (if any)
  useEffect(() => {
    if (!canRate) return;
    userFetch(`/api/furniture/${item.id}`)
      .then(r => r.json())
      .then(p => { if (p.myRating) setExisting(p.myRating); })
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [item.id, canRate]);

  const submit = async () => {
    if (!pick) return;
    setSaving(true);
    try {
      const res = await userFetch(`/api/furniture/${item.id}/rate`, {
        method: 'POST',
        body: JSON.stringify({ stars: pick, comment }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Could not save rating');
      setExisting({ stars: pick, comment });
    } catch (err) {
      alert(err.message);
    } finally {
      setSaving(false);
    }
  };

  const itemName = localizedField(item, 'name', lang);

  if (!canRate) {
    return <div className="cabinet-item"><span className="ci-name">{item.quantity}× {itemName}</span></div>;
  }

  return (
    <div className="cabinet-item">
      <div className="ci-top">
        <span className="ci-name">{item.quantity}× {itemName}</span>
        {existing ? (
          // Final, read-only rating
          <span className="ci-rate">
            <StarDisplay value={existing.stars} />
            <span className="ci-hint">{t('account.yourRating')}</span>
          </span>
        ) : !loading && (
          <span className="stars-input sm">
            {[1, 2, 3, 4, 5].map(n => (
              <button
                type="button"
                key={n}
                className={`star ${pick >= n ? 'full' : 'empty'}`}
                onClick={() => setPick(n)}
                title={`${n} ★`}
              >★</button>
            ))}
          </span>
        )}
      </div>

      {existing ? (
        existing.comment ? <p className="ci-comment">“{existing.comment}”</p> : null
      ) : !loading && (
        <div className="ci-form">
          <input
            type="text"
            className="ci-comment-input"
            placeholder={t('rating.commentPlaceholder')}
            value={comment}
            onChange={(e) => setComment(e.target.value)}
          />
          <button className="ci-submit" onClick={submit} disabled={!pick || saving}>
            {saving ? t('account.saving') : t('account.submit')}
          </button>
        </div>
      )}
    </div>
  );
}

// Account cabinet — liked items + order history
function AccountModal({ user, onClose, onLogout, onSelectProduct, onToggleFavorite, onAddressSaved }) {
  const t = useT();
  const { lang } = useContext(LangContext);
  const [tab, setTab] = useState('likes');
  const [likes, setLikes] = useState([]);
  const [orders, setOrders] = useState([]);
  const [addr, setAddr] = useState(() => ({ ...BLANK_ADDRESS, ...(user.shippingAddress || {}) }));
  const [addrStatus, setAddrStatus] = useState(''); // '', 'saving', 'saved'

  useEffect(() => {
    userFetch('/api/me/likes').then(r => r.json()).then(setLikes).catch(() => {});
    userFetch('/api/me/orders').then(r => r.json()).then(setOrders).catch(() => {});
  }, []);

  const setAddrField = (k) => (e) => { setAddr(a => ({ ...a, [k]: e.target.value })); setAddrStatus(''); };

  const saveAddress = async () => {
    setAddrStatus('saving');
    try {
      const res = await userFetch('/api/me/address', { method: 'PUT', body: JSON.stringify({ address: addr }) });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Failed');
      setAddrStatus('saved');
      if (onAddressSaved) onAddressSaved(data.shippingAddress); // so checkout reuses it
    } catch {
      setAddrStatus('');
      alert('Could not save address. Please try again.');
    }
  };

  return (
    <div className="cart-panel" onClick={onClose}>
      <div className="cart-content account-content" onClick={(e) => e.stopPropagation()}>
        <div className="cart-header">
          <h2>{t('account.title')}</h2>
          <button onClick={onClose}>✕</button>
        </div>

        <div className="account-profile">
          {user.picture
            ? <img src={user.picture} alt="" className="account-avatar lg" referrerPolicy="no-referrer" />
            : <span className="account-avatar lg fallback">{(user.name || 'U')[0]}</span>}
          <div>
            <div className="account-pname">{user.name}</div>
            <div className="account-pemail">{user.email}</div>
          </div>
          <button className="logout-link" onClick={onLogout}>{t('account.logout')}</button>
        </div>

        <div className="account-tabs">
          <button className={tab === 'likes' ? 'active' : ''} onClick={() => setTab('likes')}>♥ {t('account.liked')} ({likes.length})</button>
          <button className={tab === 'orders' ? 'active' : ''} onClick={() => setTab('orders')}>📦 {t('account.orders')} ({orders.length})</button>
          <button className={tab === 'address' ? 'active' : ''} onClick={() => setTab('address')}>📍 {t('account.address')}</button>
        </div>

        <div className="account-body">
          {tab === 'likes' && (
            likes.length === 0 ? <p className="empty-cart">{t('account.noLikes')}</p> : (
              <div className="account-likes">
                {likes.map(p => (
                  <div key={p.id} className="account-like-card" onClick={() => { onSelectProduct(p); onClose(); }}>
                    <img src={p.image} alt={localizedField(p, 'name', lang)} />
                    <div className="al-info">
                      <h4>{localizedField(p, 'name', lang)}</h4>
                      <p>${(p.salePrice || p.price).toFixed(2)}</p>
                    </div>
                    <button className="al-unlike" onClick={(e) => {
                      e.stopPropagation();
                      onToggleFavorite(p.id);
                      setLikes(prev => prev.filter(x => x.id !== p.id));
                    }}>✕</button>
                  </div>
                ))}
              </div>
            )
          )}
          {tab === 'orders' && (
            orders.length === 0 ? <p className="empty-cart">{t('account.noOrders')}</p> : (
              <div className="account-orders">
                {orders.map(o => (
                  <div key={o.id} className="account-order">
                    <div className="ao-head">
                      <span className="ao-ref">{o.reference}</span>
                      <span className={`pill ${o.status}`}>{o.status}</span>
                    </div>
                    <div className="ao-meta">{(o.createdAt || '').slice(0, 10)} · {o.items.reduce((n, i) => n + i.quantity, 0)} {t('account.item')} · ${o.total.toFixed(2)}</div>
                    <div className="ao-items-list">
                      {o.items.map((it, idx) => (
                        <CabinetRateRow key={idx} item={it} canRate={o.status === 'paid'} />
                      ))}
                    </div>
                    {o.status === 'paid' && <div className="ao-rate-hint">{t('account.rateHint')}</div>}
                  </div>
                ))}
              </div>
            )
          )}
          {tab === 'address' && (
            <div className="account-address">
              <p className="addr-intro">{t('account.addressIntro')}</p>
              <input type="text" placeholder={t('form.street')} value={addr.line1} onChange={setAddrField('line1')} className="checkout-input" />
              <input type="text" placeholder={t('form.apt')} value={addr.line2} onChange={setAddrField('line2')} className="checkout-input" />
              <div className="checkout-row">
                <input type="text" placeholder={t('form.city')} value={addr.city} onChange={setAddrField('city')} className="checkout-input" />
                <input type="text" placeholder={t('form.state')} value={addr.state} onChange={setAddrField('state')} className="checkout-input" />
              </div>
              <div className="checkout-row">
                <input type="text" placeholder={t('form.postal')} value={addr.postal} onChange={setAddrField('postal')} className="checkout-input" />
                <input type="text" placeholder={t('form.country')} value={addr.country} onChange={setAddrField('country')} className="checkout-input" />
              </div>
              <button className="checkout-btn" onClick={saveAddress} disabled={addrStatus === 'saving'}>
                {addrStatus === 'saving' ? t('account.saving') : addrStatus === 'saved' ? '✓ ' + t('account.addressSaved') : t('account.saveAddress')}
              </button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// Main App
function App() {
  const { lang } = useContext(LangContext);
  const t = useT();
  const [allProducts, setAllProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);
  const [selectedCategory, setSelectedCategory] = useState('All');
  const [selectedCollection, setSelectedCollection] = useState(null);
  const [allCollections, setAllCollections] = useState([]);
  const [selectedProduct, setSelectedProduct] = useState(null);
  const [cart, setCart] = useState(() => {
    const saved = localStorage.getItem('beejou-cart');
    return saved ? JSON.parse(saved) : [];
  });
  const [favorites, setFavorites] = useState(() => {
    const saved = localStorage.getItem('beejou-favorites');
    return saved ? JSON.parse(saved) : [];
  });
  const [showCart, setShowCart] = useState(false);
  const [search, setSearch] = useState('');
  const [priceRange, setPriceRange] = useState({ min: 0, max: 100 });
  const [selectedColors, setSelectedColors] = useState([]);
  const [sortBy, setSortBy] = useState('featured');

  // Auth / account
  const [user, setUser] = useState(null);
  const [authConfig, setAuthConfig] = useState(null);
  const [showLogin, setShowLogin] = useState(false);
  const [showAccount, setShowAccount] = useState(false);

  useEffect(() => {
    fetchProducts();
  }, []);

  // Load auth config + restore an existing session on mount
  useEffect(() => {
    fetch('/api/auth/config').then(r => r.json()).then(setAuthConfig).catch(() => {});
    if (localStorage.getItem(USER_TOKEN_KEY)) {
      userFetch('/api/me').then(r => r.ok ? r.json() : Promise.reject())
        .then(({ user, likedIds }) => { setUser(user); setFavorites(likedIds); })
        .catch(() => localStorage.removeItem(USER_TOKEN_KEY));
    }
  }, []);

  // Complete Google sign-in: exchange credential, merging local favorites
  const handleGoogleCredential = async (credential) => {
    try {
      const res = await userFetch('/api/auth/google', {
        method: 'POST',
        body: JSON.stringify({ credential, mergeLikes: favorites }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Sign-in failed');
      localStorage.setItem(USER_TOKEN_KEY, data.token);
      setUser(data.user);
      setFavorites(data.likedIds);
      setShowLogin(false);
    } catch (err) {
      alert(err.message);
    }
  };

  const handleLogout = async () => {
    try { await userFetch('/api/logout', { method: 'POST' }); } catch {}
    localStorage.removeItem(USER_TOKEN_KEY);
    setUser(null);
    setShowAccount(false);
  };

  useEffect(() => {
    localStorage.setItem('beejou-cart', JSON.stringify(cart));
  }, [cart]);

  useEffect(() => {
    localStorage.setItem('beejou-favorites', JSON.stringify(favorites));
  }, [favorites]);

  useEffect(() => {
    filterProducts();
  }, [selectedCategory, selectedCollection, search, allProducts, priceRange, selectedColors, sortBy]);

  const fetchProducts = async () => {
    try {
      const [productsRes, collectionsRes] = await Promise.all([
        fetch(`${window.location.origin}/api/furniture`),
        fetch(`${window.location.origin}/api/collections`)
      ]);
      const productsData = await productsRes.json();
      const collectionsData = await collectionsRes.json();
      setAllProducts(productsData);
      setAllCollections(collectionsData);
      setFilteredProducts(productsData);
      // Initialize price range from data
      const prices = productsData.map(p => p.salePrice || p.price);
      if (prices.length) {
        setPriceRange({ min: Math.floor(Math.min(...prices)), max: Math.ceil(Math.max(...prices)) });
      }
    } catch (error) {
      console.error('Error:', error);
    }
  };

  const filterProducts = () => {
    let filtered = allProducts;

    if (selectedCollection) {
      filtered = filtered.filter(p => p.collection === selectedCollection);
    } else if (selectedCategory !== 'All') {
      filtered = filtered.filter(p => p.category === selectedCategory);
    }

    if (search) {
      const q = search.toLowerCase();
      filtered = filtered.filter(p => {
        // Search across name, description, category, color — and translated names —
        // all null-safe (some products have no description).
        const haystack = [
          p.name, p.description, p.category, p.color,
          p.name_pl, p.name_uk, p.description_pl, p.description_uk,
        ].filter(Boolean).join(' ').toLowerCase();
        return haystack.includes(q);
      });
    }

    // Price filter
    filtered = filtered.filter(p => {
      const price = p.salePrice || p.price;
      return price >= priceRange.min && price <= priceRange.max;
    });

    // Color filter
    if (selectedColors.length > 0) {
      filtered = filtered.filter(p => selectedColors.includes(p.color));
    }

    // Sorting
    filtered = [...filtered];
    if (sortBy === 'price-low') {
      filtered.sort((a, b) => (a.salePrice || a.price) - (b.salePrice || b.price));
    } else if (sortBy === 'price-high') {
      filtered.sort((a, b) => (b.salePrice || b.price) - (a.salePrice || a.price));
    } else if (sortBy === 'rating') {
      filtered.sort((a, b) => b.rating - a.rating);
    }

    setFilteredProducts(filtered);
  };

  const handleAddToCart = (product, quantityDelta = 1) => {
    setCart(prev => {
      const existing = prev.find(item => item.id === product.id);
      if (existing) {
        const newQty = existing.quantity + quantityDelta;
        if (newQty <= 0) {
          return prev.filter(item => item.id !== product.id);
        }
        return prev.map(item =>
          item.id === product.id ? { ...item, quantity: newQty } : item
        );
      } else {
        return [...prev, { ...product, quantity: quantityDelta }];
      }
    });
  };

  const handleUpdateCart = (productId, newQuantity) => {
    if (newQuantity <= 0) {
      setCart(prev => prev.filter(item => item.id !== productId));
    } else {
      setCart(prev =>
        prev.map(item =>
          item.id === productId ? { ...item, quantity: newQuantity } : item
        )
      );
    }
  };

  // Open a product and record a view
  const handleSelectProduct = (product) => {
    setSelectedProduct(product);
    if (product && product.id) {
      fetch(`/api/furniture/${product.id}/view`, { method: 'POST' }).catch(() => {});
    }
  };

  // Toggle favorite locally + record the like/unlike on the server
  const handleToggleFavorite = (id) => {
    const liked = !favorites.includes(id);
    setFavorites(prev => liked ? [...prev, id] : prev.filter(fid => fid !== id));
    // userFetch attaches the session token so likes persist to the account
    userFetch(`/api/furniture/${id}/like`, {
      method: 'POST',
      body: JSON.stringify({ liked }),
    }).catch(() => {});
  };

  // Order paid successfully — clear cart and notify the shopper
  const handleOrderComplete = (reference) => {
    setCart([]);
    setShowCart(false);
    alert(translate(lang, 'checkout.thankYou', { ref: reference }));
    fetchProducts();
  };

  // Nav: leave any cart/product view, then smooth-scroll to the target section
  const handleNavigate = (section) => {
    setShowCart(false);
    setSelectedProduct(null);
    setShowAccount(false);
    // wait a tick for the shop view to render before scrolling
    setTimeout(() => {
      const target = section === 'home'
        ? document.querySelector('.app-pro')
        : document.getElementById(section);
      if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 50);
  };

  // Handle return from Stripe Checkout (?order=...&session_id=...)
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const reference = params.get('order');
    const sessionId = params.get('session_id');
    if (reference && sessionId) {
      fetch('/api/checkout/confirm', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ reference, sessionId }),
      })
        .then(r => r.json())
        .then(d => {
          if (d.ok) {
            setCart([]);
            alert(translate(lang, 'checkout.thankYou', { ref: reference }));
          } else {
            alert(d.error || 'We could not confirm your payment.');
          }
          window.history.replaceState({}, '', '/');
        })
        .catch(() => {});
    } else if (params.get('canceled')) {
      window.history.replaceState({}, '', '/');
    }
  }, []);

  const categories = ['All', ...new Set(allProducts.map(p => p.category))];
  const availableColors = [...new Set(allProducts.map(p => p.color).filter(Boolean))];
  const allPrices = allProducts.map(p => p.salePrice || p.price);
  const priceBounds = allPrices.length
    ? { min: Math.floor(Math.min(...allPrices)), max: Math.ceil(Math.max(...allPrices)) }
    : { min: 0, max: 100 };

  const toggleColor = (color) => {
    setSelectedColors(prev =>
      prev.includes(color) ? prev.filter(c => c !== color) : [...prev, color]
    );
  };

  const clearFilters = () => {
    setSelectedColors([]);
    setPriceRange(priceBounds);
    setSelectedCategory('All');
    setSearch('');
    setSortBy('featured');
  };

  return (
    <div className="app-pro">
      <Header
        cart={cart}
        onCartClick={() => setShowCart(!showCart)}
        user={user}
        onAccountClick={() => setShowAccount(true)}
        onLoginClick={() => setShowLogin(true)}
        onNavigate={handleNavigate}
      />

      {showLogin && (
        <LoginModal
          authConfig={authConfig}
          onCredential={handleGoogleCredential}
          onClose={() => setShowLogin(false)}
        />
      )}

      {showAccount && user && (
        <AccountModal
          user={user}
          onClose={() => setShowAccount(false)}
          onLogout={handleLogout}
          onSelectProduct={handleSelectProduct}
          onToggleFavorite={handleToggleFavorite}
          onAddressSaved={(addr) => setUser(u => ({ ...u, shippingAddress: addr }))}
        />
      )}

      <main className="main-content">
        {showCart ? (
          <div className="container-fluid">
            <ShoppingCart
              cart={cart}
              onClose={() => setShowCart(false)}
              onUpdateCart={handleUpdateCart}
              onOrderComplete={handleOrderComplete}
              user={user}
            />
          </div>
        ) : selectedProduct ? (
          <div className="container-fluid">
            <ProductDetailModal
              product={selectedProduct}
              onClose={() => setSelectedProduct(null)}
              onAddToCart={handleAddToCart}
              cart={cart}
              user={user}
              onLoginClick={() => setShowLogin(true)}
            />
          </div>
        ) : (
          <>
          <HeroSection
            onShopClick={() => handleNavigate('shop')}
            allCategories={categories}
            selectedCategory={selectedCategory}
            onCategoryChange={(cat) => {
              setSelectedCategory(cat);
              setSelectedCollection(null);
              handleNavigate('shop');
            }}
          />
          <div className="shop-layout" id="shop">
            <FilterSidebar
              priceBounds={priceBounds}
              priceRange={priceRange}
              onPriceChange={setPriceRange}
              availableColors={availableColors}
              selectedColors={selectedColors}
              onToggleColor={toggleColor}
              onClear={clearFilters}
            />

            <div className="shop-main">
              <div className="shop-toolbar">
                <div className="search-wrap">
                  <span className="search-icon">⚲</span>
                  <input
                    type="text"
                    placeholder={t('shop.search')}
                    value={search}
                    onChange={(e) => setSearch(e.target.value)}
                    className="search-input"
                  />
                </div>
                <div className="toolbar-right">
                  <span className="result-count">{filteredProducts.length} {t('account.item')}</span>
                  <select className="sort-select" value={sortBy} onChange={(e) => setSortBy(e.target.value)}>
                    <option value="featured">{t('sort.featured')}</option>
                    <option value="price-low">{t('sort.priceLow')}</option>
                    <option value="price-high">{t('sort.priceHigh')}</option>
                    <option value="rating">{t('sort.topRated')}</option>
                  </select>
                </div>
              </div>

              <ProductGrid
                products={filteredProducts}
                onSelectProduct={handleSelectProduct}
                favorites={favorites}
                onToggleFavorite={handleToggleFavorite}
                onAddToCart={handleAddToCart}
              />
            </div>
          </div>
          </>
        )}

        {!showCart && !selectedProduct && (
          <>
            <div id="collections">
              <FeaturedCollections
                collections={allCollections}
                onSelectCollection={(collName) => {
                  setSelectedCollection(collName);
                  setSelectedCategory('All');
                }}
                selectedCollection={selectedCollection}
              />
            </div>
            <AboutSection />
            <ContactSection user={user} />
          </>
        )}
      </main>

      <footer className="footer-pro">
        <p>{t('footer')}<a href="https://www.etsy.com/shop/BeeeJou">{t('footer.etsy')}</a></p>
      </footer>

      <CookieConsent />
    </div>
  );
}

// Language provider — holds the active language and persists the choice
function LangProvider({ children }) {
  const [lang, setLangState] = useState(() => {
    const saved = localStorage.getItem(LANG_KEY);
    return LANGUAGES.some(l => l.code === saved) ? saved : 'en';
  });
  const setLang = (code) => {
    setLangState(code);
    localStorage.setItem(LANG_KEY, code);
    document.documentElement.lang = code;
  };
  useEffect(() => { document.documentElement.lang = lang; }, [lang]);
  return <LangContext.Provider value={{ lang, setLang }}>{children}</LangContext.Provider>;
}

ReactDOM.createRoot(document.getElementById('root')).render(
  <LangProvider><App /></LangProvider>
);
