'use client';

/**
 * =============================================================================
 * GLOBAL CART SYSTEM — Shahi Kitchen
 * =============================================================================
 * 
 * This file implements a production-grade, persistent shopping cart using:
 *   • React Context + useReducer (predictable state machine)
 *   • localStorage persistence (survives page refresh / browser restart)
 *   • Sonner toasts with "View Cart" action
 *   • Derived totals (totalItems, totalPrice) computed on every render
 * 
 * WHY THIS ARCHITECTURE?
 * - useReducer gives us a single source of truth and easy debugging (time-travel capable)
 * - Context lets ANY component (menu cards, navbar icon, drawer, future checkout)
 *   access cart state without prop drilling
 * - localStorage key is namespaced ("shahi-kitchen-cart") so multiple sites on same
 *   domain won't collide
 * 
 * IMPORTANT INTEGRATION POINTS:
 * - CartProvider is mounted ONCE in app/layout.tsx (root of the tree)
 * - useCart() hook is used in:
 *     • app/menu/page.tsx          → addToCart() on every dish
 *     • components/Navbar.tsx      → shows live count + opens drawer
 *     • components/CartDrawer.tsx  → full management UI + WhatsApp ordering
 * 
 * WHATSAPP ORDER FLOW (the "checkout" for this restaurant):
 *   The cart never talks to a real payment gateway. Instead, the drawer builds a
 *   beautifully formatted message and opens https://wa.me/46709864995 with it pre-filled.
 *   This matches exactly how the reservation form on the homepage works.
 * 
 * FUTURE IMPROVEMENTS (documented for next developer):
 * - Add "special instructions" per item or for the whole order
 * - Persist cart across different devices via Supabase / Firebase (when real ordering launches)
 * - Add estimated pickup time or "order for later" picker
 * - Minimum order value enforcement
 * 
 * GOTCHAS:
 * - The localStorage restore logic runs only once on mount. It dispatches multiple
 *   actions on purpose so the reducer stays pure.
 * - Toasts are intentionally fired ONLY from addToCart(), never from restore.
 */

import React, { createContext, useContext, useReducer, useEffect, ReactNode } from 'react';
import { toast } from 'sonner';

/**
 * TYPE DEFINITIONS
 * 
 * CartItem — the shape stored in state and localStorage.
 *   image is optional because some drinks don't have photos yet.
 * 
 * CartState — minimal internal state. We derive totalItems/totalPrice in the provider
 *             so consumers never have to recalculate.
 * 
 * CartAction — discriminated union. This is what makes the reducer easy to reason about.
 */
export interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
  image?: string;
}

interface CartState {
  items: CartItem[];
  isOpen: boolean;
}

type CartAction =
  | { type: 'ADD_ITEM'; payload: Omit<CartItem, 'quantity'> }
  | { type: 'REMOVE_ITEM'; payload: string }
  | { type: 'UPDATE_QUANTITY'; payload: { id: string; quantity: number } }
  | { type: 'CLEAR_CART' }
  | { type: 'TOGGLE_CART' }
  | { type: 'OPEN_CART' }
  | { type: 'CLOSE_CART' };

interface CartContextType {
  items: CartItem[];
  isOpen: boolean;
  totalItems: number;
  totalPrice: number;
  addToCart: (item: Omit<CartItem, 'quantity'>) => void;
  removeFromCart: (id: string) => void;
  updateQuantity: (id: string, quantity: number) => void;
  clearCart: () => void;
  toggleCart: () => void;
  openCart: () => void;
  closeCart: () => void;
}

const CartContext = createContext<CartContextType | undefined>(undefined);

/**
 * THE REDUCER — Single Source of Truth for All Cart Mutations
 * 
 * This is a classic Redux-style reducer: pure, predictable, easy to test.
 * 
 * DESIGN DECISIONS:
 * - ADD_ITEM automatically increments quantity if the dish already exists
 *   (very common restaurant UX — user taps the same samosa twice)
 * - UPDATE_QUANTITY with quantity <= 0 removes the item (no negative quantities)
 * - Only the drawer can toggle isOpen. Menu cards only ever call addToCart().
 * - CLEAR_CART is exposed for the "Clear basket" buttons in the drawer header/footer.
 */
function cartReducer(state: CartState, action: CartAction): CartState {
  switch (action.type) {
    case 'ADD_ITEM': {
      const existingItem = state.items.find(item => item.id === action.payload.id);
      
      if (existingItem) {
        // Increment existing line item (most common case after first add)
        return {
          ...state,
          items: state.items.map(item =>
            item.id === action.payload.id
              ? { ...item, quantity: item.quantity + 1 }
              : item
          ),
        };
      } else {
        // Brand new line item
        return {
          ...state,
          items: [...state.items, { ...action.payload, quantity: 1 }],
        };
      }
    }

    case 'REMOVE_ITEM':
      return {
        ...state,
        items: state.items.filter(item => item.id !== action.payload),
      };

    case 'UPDATE_QUANTITY':
      if (action.payload.quantity <= 0) {
        // Treat zero or negative as "remove this line"
        return {
          ...state,
          items: state.items.filter(item => item.id !== action.payload.id),
        };
      }
      return {
        ...state,
        items: state.items.map(item =>
          item.id === action.payload.id
            ? { ...item, quantity: action.payload.quantity }
            : item
        ),
      };

    case 'CLEAR_CART':
      return { ...state, items: [] };

    case 'TOGGLE_CART':
      return { ...state, isOpen: !state.isOpen };

    case 'OPEN_CART':
      return { ...state, isOpen: true };

    case 'CLOSE_CART':
      return { ...state, isOpen: false };

    default:
      return state;
  }
}

/**
 * PERSISTENCE LAYER
 * 
 * We use a single well-namespaced localStorage key so the cart survives:
 * - Page refresh
 * - Browser restart
 * - User navigating away and coming back days later
 * 
 * The restore logic is intentionally verbose (multiple dispatches) because we want
 * the reducer to remain the only place that understands "how to add an item".
 * This keeps the restore path debuggable and future-proof.
 */
const CART_STORAGE_KEY = 'shahi-kitchen-cart';

export function CartProvider({ children }: { children: ReactNode }) {
  const [state, dispatch] = useReducer(cartReducer, {
    items: [],
    isOpen: false,
  });

  // ONE-TIME HYDRATION FROM LOCALSTORAGE
  // Runs only on initial mount. Restores previous session's cart silently (no toasts).
  useEffect(() => {
    const savedCart = localStorage.getItem(CART_STORAGE_KEY);
    if (savedCart) {
      try {
        const parsedItems = JSON.parse(savedCart);
        // We replay through the reducer so all business rules stay in one place
        parsedItems.forEach((item: CartItem) => {
          dispatch({ type: 'ADD_ITEM', payload: item });
          // If the saved quantity was > 1 we need a second dispatch to correct it
          if (item.quantity > 1) {
            dispatch({ 
              type: 'UPDATE_QUANTITY', 
              payload: { id: item.id, quantity: item.quantity } 
            });
          }
        });
      } catch (error) {
        console.error('Failed to load cart from localStorage');
      }
    }
  }, []);

  // AUTO-PERSIST ON EVERY CHANGE
  // Extremely simple and reliable. In a future real ordering system you would
  // debounce this and also sync to a backend.
  useEffect(() => {
    localStorage.setItem(CART_STORAGE_KEY, JSON.stringify(state.items));
  }, [state.items]);

  /**
   * DERIVED STATE (recomputed on every render — cheap and always fresh)
   */
  const totalItems = state.items.reduce((sum, item) => sum + item.quantity, 0);
  const totalPrice = state.items.reduce((sum, item) => sum + item.price * item.quantity, 0);

  /**
   * PUBLIC API — these functions are what the rest of the app calls.
   * 
   * addToCart is special: it also triggers the beautiful Sonner toast with
   * an action button that opens the drawer. This is the primary feedback mechanism.
   */
  const addToCart = (item: Omit<CartItem, 'quantity'>) => {
    dispatch({ type: 'ADD_ITEM', payload: item });
    toast.success(`Added ${item.name} to cart`, {
      description: `${item.price} kr`,
      action: {
        label: "View Cart",
        onClick: () => dispatch({ type: 'OPEN_CART' }),
      },
    });
  };

  const removeFromCart = (id: string) => {
    dispatch({ type: 'REMOVE_ITEM', payload: id });
  };

  const updateQuantity = (id: string, quantity: number) => {
    dispatch({ type: 'UPDATE_QUANTITY', payload: { id, quantity } });
  };

  const clearCart = () => {
    dispatch({ type: 'CLEAR_CART' });
  };

  const toggleCart = () => {
    dispatch({ type: 'TOGGLE_CART' });
  };

  const openCart = () => {
    dispatch({ type: 'OPEN_CART' });
  };

  const closeCart = () => {
    dispatch({ type: 'CLOSE_CART' });
  };

  /**
   * CONTEXT PROVIDER VALUE
   * Everything a consumer might need is exposed here.
   * We intentionally do NOT expose dispatch directly — all mutations go through
   * the named methods above (better encapsulation + future-proofing).
   */
  return (
    <CartContext.Provider
      value={{
        items: state.items,
        isOpen: state.isOpen,
        totalItems,
        totalPrice,
        addToCart,
        removeFromCart,
        updateQuantity,
        clearCart,
        toggleCart,
        openCart,
        closeCart,
      }}
    >
      {children}
    </CartContext.Provider>
  );
}

/**
 * useCart — The only way the rest of the app should consume cart state/actions.
 * 
 * Throws a clear error if someone tries to use it outside the provider tree
 * (catches 99% of integration mistakes during development).
 */
export function useCart() {
  const context = useContext(CartContext);
  if (context === undefined) {
    throw new Error('useCart must be used within a CartProvider');
  }
  return context;
}
