/**
 * ============================================
 * CART CONTEXT (State Management)
 * ============================================
 * 
 * FOR SHOPWARE DEVELOPERS:
 * In Shopware Twig, the cart is available via `page.cart` in templates.
 * In React, we use "Context" - think of it like a global variable
 * that any component can access.
 * 
 * This replaces: CartService, cart.html.twig, cart subscribers
 */

'use client';

import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import {
  Cart,
  getCart,
  getContext,
  addToCart as apiAddToCart,
  addPromotion as apiAddPromotion,
  updateCartItem as apiUpdateCartItem,
  removeFromCart as apiRemoveFromCart,
  getContextToken,
} from './shopware-api';

// Define what data and functions the cart context provides
interface CartContextType {
  cart: Cart | null;
  isLoading: boolean;
  isCartOpen: boolean;
  itemCount: number;
  addToCart: (productId: string, quantity?: number) => Promise<void>;
  applyPromoCode: (code: string) => Promise<void>;
  updateQuantity: (lineItemId: string, quantity: number) => Promise<void>;
  removeItem: (lineItemId: string) => Promise<void>;
  refreshCart: () => Promise<void>;
  openCart: () => void;
  closeCart: () => void;
  toggleCart: () => void;
}

// Create the context (like creating a service container)
const CartContext = createContext<CartContextType | undefined>(undefined);

/**
 * CartProvider wraps your app and makes cart data available everywhere
 * 
 * Think of it like Shopware's CartService but for React.
 * Any component inside <CartProvider> can access the cart.
 */
export function CartProvider({ children }: { children: React.ReactNode }) {
  const [cart, setCart] = useState<Cart | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [isCartOpen, setIsCartOpen] = useState(false);

  // Calculate total items in cart
  const itemCount = cart?.lineItems?.reduce((sum, item) => sum + item.quantity, 0) || 0;

  // Load cart on first render (like onMounted in Vue)
  const refreshCart = useCallback(async () => {
    try {
      const token = getContextToken();
      if (token) {
        const cartData = await getCart();
        setCart(cartData);
      }
    } catch (error) {
      console.error('Failed to load cart:', error);
    }
  }, []);

  // Initialize context session on first load.
  // This ensures Shopware creates a proper session with correct tax settings
  // BEFORE any cart operations (addToCart, etc.) happen.
  useEffect(() => {
    async function initSession() {
      const token = getContextToken();
      if (!token) {
        try {
          await getContext();
        } catch {
          // Silently fail — session will be created on first cart operation
        }
      }
      refreshCart();
    }
    initSession();
  }, [refreshCart]);

  // Apply promotion/discount code
  const applyPromoCode = useCallback(async (code: string) => {
    setIsLoading(true);
    try {
      const updatedCart = await apiAddPromotion(code);
      setCart(updatedCart);
      // Shopware returns messages inside cart.errors — including success notices.
      // Only treat level >= 20 (or type === 'error') as real failures.
      const errors = Object.values(updatedCart?.errors || {});
      const promoError = errors.find((e: any) => {
        const isError = e?.level === 20 || e?.type === 'error';
        const isPromoRelated =
          e?.messageKey?.toLowerCase().includes('promotion') ||
          e?.message?.toLowerCase().includes('promotion') ||
          e?.message?.toLowerCase().includes('code') ||
          e?.messageKey?.toLowerCase().includes('discount');
        return isError && isPromoRelated;
      }) as any;
      if (promoError) {
        throw new Error(promoError.message || 'Promotion could not be applied.');
      }
    } finally {
      setIsLoading(false);
    }
  }, []);

  // Add product to cart
  const addToCart = useCallback(async (productId: string, quantity: number = 1) => {
    setIsLoading(true);
    try {
      const updatedCart = await apiAddToCart(productId, quantity);
      setCart(updatedCart);
      setIsCartOpen(true); // Open cart drawer when item added
    } catch (error) {
      console.error('Failed to add to cart:', error);
      throw error;
    } finally {
      setIsLoading(false);
    }
  }, []);

  // Update item quantity
  const updateQuantity = useCallback(async (lineItemId: string, quantity: number) => {
    setIsLoading(true);
    try {
      const updatedCart = await apiUpdateCartItem(lineItemId, quantity);
      setCart(updatedCart);
    } catch (error) {
      console.error('Failed to update cart:', error);
      throw error;
    } finally {
      setIsLoading(false);
    }
  }, []);

  // Remove item
  const removeItem = useCallback(async (lineItemId: string) => {
    setIsLoading(true);
    try {
      const updatedCart = await apiRemoveFromCart(lineItemId);
      setCart(updatedCart);
    } catch (error) {
      console.error('Failed to remove from cart:', error);
      throw error;
    } finally {
      setIsLoading(false);
    }
  }, []);

  const openCart = useCallback(() => setIsCartOpen(true), []);
  const closeCart = useCallback(() => setIsCartOpen(false), []);
  const toggleCart = useCallback(() => setIsCartOpen(prev => !prev), []);

  // Provide all cart data and functions to child components
  return (
    <CartContext.Provider
      value={{
        cart,
        isLoading,
        isCartOpen,
        itemCount,
        addToCart,
        applyPromoCode,
        updateQuantity,
        removeItem,
        refreshCart,
        openCart,
        closeCart,
        toggleCart,
      }}
    >
      {children}
    </CartContext.Provider>
  );
}

/**
 * useCart() hook - use this in any component to access the cart
 * 
 * Example usage:
 *   const { cart, addToCart, itemCount } = useCart();
 * 
 * This is like accessing CartService in Shopware:
 *   $this->cartService->getCart(...)
 */
export function useCart() {
  const context = useContext(CartContext);
  if (!context) {
    throw new Error('useCart must be used within a CartProvider');
  }
  return context;
}
