import { createContext, useContext, useState, FC, ReactNode } from 'react';
import { getStorage, setStorage } from '../utils/helpers/storage';
import { ProductData } from '../utils/interface/productInterface';

export interface ICart {
  product: ProductData;
  quantity: number;
}

interface IStorage {
  cartStorage: ICart[];
  totalPrice: number;
  totalQuantity: number;
}

interface IStorageDispatch {
  addCartValue: (x: ProductData, y: number) => void;
  clearCart: () => void;
  removeCartValue: (x: string) => void;
  updateItemQuantity: (x: string, y: number) => void;
}

interface Props {
  children: ReactNode;
}

const StorageContext = createContext<IStorage>({
  cartStorage: [],
  totalPrice: 0,
  totalQuantity: 0,
});

const StorageDispatchContext = createContext<IStorageDispatch>({
  addCartValue: (product: ProductData, quantity: number) => {},
  clearCart: () => {},
  removeCartValue: (productId: string) => {},
  updateItemQuantity: (productId: string, quantity: number) => {},
});

export const useStore = () => {
  return useContext(StorageContext);
};
export const useStoreUpdate = () => {
  return useContext(StorageDispatchContext);
};

const useStorage = () => {
  const CART_KEY = 'cart-products';
  const [cartStorage, setCartStorage] = useState<ICart[]>(getStorage(CART_KEY));
  const [totalPrice, setTotalPrice] = useState<number>(() => {
    const cart: ICart[] = getStorage(CART_KEY);

    if (cart && cart.length) {
      return cart
        .map((entry) => entry?.product.price * entry?.quantity)
        .reduce((accum: number, curValue: number) => accum + curValue);
    } else {
      return 0;
    }
  });

  const [totalQuantity, setTotalQuantity] = useState<number>(() => {
    const cart = getStorage(CART_KEY);

    if (cart && cart.length) {
      return cart.length;
    } else {
      return 0;
    }
  });

  const addCartValue = (product: ProductData, quantity: number) => {
    const items: ICart[] = getStorage(CART_KEY);

    if (!items) {
      setStorage(CART_KEY, { product, quantity });
    } else {
      const isItemDuplicate = items.some(
        (item) => item.product.customID === product.customID
      );

      if (!isItemDuplicate) {
        items.push({ product, quantity });
        setTotalQuantity((prevState: number) => prevState + 1);
        setStorage(CART_KEY, items);
      } else {
        return;
      }
    }

    const newTotalPrice = items
      .map((entry) => entry?.product.price * entry?.quantity)
      .reduce((accum, curValue) => accum + curValue);

    setTotalPrice(newTotalPrice);

    setCartStorage(items);
  };

  const updateItemQuantity = (productId: string, quantity: number) => {
    if (quantity < 0) return;
    const items: ICart[] = getStorage(CART_KEY);
    let updatedItems = items;

    if (items) {
      updatedItems = items.map((entry) => {
        if (entry?.product.customID === productId) {
          console.log('true');
          entry.quantity = quantity;
        }
        return entry;
      });

      setStorage(CART_KEY, updatedItems);
    }

    const newTotalPrice = updatedItems
      .map((entry) => entry?.product.price * entry?.quantity)
      .reduce((accum, curValue) => accum + curValue);

    setTotalPrice(newTotalPrice);
    setCartStorage(updatedItems);
  };

  const clearCart = () => {
    setStorage(CART_KEY, {});
    setTotalQuantity(0);
    setTotalPrice(0);
    setCartStorage([]);
  };

  const removeCartValue = (productId: string) => {
    const items: ICart[] = getStorage(CART_KEY);

    const newStorage = items?.filter(
      (item) => item.product.customID !== productId
    );

    if (newStorage.length === 0) {
      setTotalPrice(0);
    } else {
      const newTotalPrice = newStorage
        .map((entry) => entry?.product.price * entry?.quantity)
        .reduce((accum, curValue) => accum + curValue);
      setTotalPrice(newTotalPrice);
    }
    setTotalQuantity((prevState: number) => prevState - 1);
    setStorage(CART_KEY, newStorage);
    setCartStorage(newStorage);
  };

  return {
    addCartValue,
    cartStorage,
    totalPrice,
    totalQuantity,
    clearCart,
    removeCartValue,
    setCartStorage,
    updateItemQuantity,
  };
};

const StorageProvider: FC<Props> = ({ children }) => {
  const {
    cartStorage,
    totalPrice,
    totalQuantity,
    addCartValue,
    clearCart,
    setCartStorage,
    removeCartValue,
    updateItemQuantity,
  } = useStorage();

  return (
    <StorageContext.Provider value={{ cartStorage, totalPrice, totalQuantity }}>
      <StorageDispatchContext.Provider
        value={{
          addCartValue,
          clearCart,
          removeCartValue,
          updateItemQuantity,
        }}
      >
        {children}
      </StorageDispatchContext.Provider>
    </StorageContext.Provider>
  );
};

export default StorageProvider;
