import { createContext, useContext, useState, FC, ReactNode } from 'react';
import { getSStorage, setSStorage } from '../utils/helpers/storage';
import { ShippingData } from '../utils/interface/orderInterface';
import { ProductData } from '../utils/interface/productInterface';
import { UserData } from '../utils/interface/userInterface';

interface Props {
  children: ReactNode;
}

interface Products {
  product: ProductData;
  quantity: number;
}

interface CheckoutData {
  products: Products[];
  userInfo: ShippingData;
  userID: string;
}

interface OrderData {
  products: Array<ProductData>;
  time: string;
  shippingAddress: ShippingData;
  totalPrice: number;
  numberOfItems: number;
  fulfilled: boolean;
  owner: string;
  stripeCheckoutId: string;
}

interface ICheckout {
  checkoutStorage: CheckoutData;
}

interface ICheckoutDispatch {
  addCheckoutValue: (x: Products[], y: ShippingData, z: string) => void;
  changeContact: (x: string) => void;
  changeShippingData: (x: ShippingData) => void;
  clearCheckout: () => void;
  parseCheckoutValue: () => OrderData;
}

const CheckoutContext = createContext<ICheckout>({
  checkoutStorage: {} as CheckoutData,
});

const CheckoutDispatchContext = createContext<ICheckoutDispatch>({
  addCheckoutValue: (
    products: Products[],
    userInfo: ShippingData,
    userID: string
  ) => {},
  changeContact: (email: string) => {},
  changeShippingData: (shippingData: ShippingData) => {},
  clearCheckout: () => {},
  parseCheckoutValue: () => {
    return {} as OrderData;
  },
});

export const useCheckoutData = () => {
  return useContext(CheckoutContext);
};
export const useCheckoutDataUpdate = () => {
  return useContext(CheckoutDispatchContext);
};

const useCheckout = () => {
  const CHECKOUT_KEY = 'checkout-data';
  const [checkoutStorage, setCheckoutStorage] = useState<CheckoutData>(
    getSStorage(CHECKOUT_KEY)
  );

  const addCheckoutValue = (
    products: Products[],
    userInfo: ShippingData,
    userID: string
  ) => {
    setSStorage(CHECKOUT_KEY, { products, userInfo, userID });

    setCheckoutStorage({ products, userInfo, userID });
  };

  const clearCheckout = () => {
    setSStorage(CHECKOUT_KEY, {});
    setCheckoutStorage({} as CheckoutData);
  };

  const parseCheckoutValue = () => {
    const items = checkoutStorage;

    const date = new Date();
    const dataToStore = {
      products: items?.products?.map((el) => el.product),
      time: date.toLocaleDateString(),
      shippingAddress: items?.userInfo,
      totalPrice: items?.products
        ?.map((entry) => entry?.product.price * entry?.quantity)
        ?.reduce((accum, curValue) => accum + curValue),
      numberOfItems: items?.products
        ?.map((entry) => entry?.quantity)
        ?.reduce((accum, curValue) => accum + curValue),
      fulfilled: false,
      owner: items?.userID,
      stripeCheckoutId: `Stripe test4`,
    };

    return dataToStore;
  };

  const changeContact = (email: string) => {
    const items: CheckoutData = getSStorage(CHECKOUT_KEY);

    items.userInfo.email = email;
    setSStorage(CHECKOUT_KEY, { ...items });

    setCheckoutStorage(items);
  };

  const changeShippingData = (shippingData: ShippingData) => {
    const items: CheckoutData = getSStorage(CHECKOUT_KEY);

    items.userInfo = { ...shippingData, email: items.userInfo.email };

    setSStorage(CHECKOUT_KEY, { ...items });

    setCheckoutStorage(items);
  };

  return {
    addCheckoutValue,
    clearCheckout,
    parseCheckoutValue,
    changeContact,
    changeShippingData,
    checkoutStorage,
  };
};

const CheckoutProvider: FC<Props> = ({ children }) => {
  const {
    checkoutStorage,
    addCheckoutValue,
    clearCheckout,
    parseCheckoutValue,
    changeContact,
    changeShippingData,
  } = useCheckout();

  return (
    <CheckoutContext.Provider value={{ checkoutStorage }}>
      <CheckoutDispatchContext.Provider
        value={{
          addCheckoutValue,
          clearCheckout,
          parseCheckoutValue,
          changeContact,
          changeShippingData,
        }}
      >
        {children}
      </CheckoutDispatchContext.Provider>
    </CheckoutContext.Provider>
  );
};

export default CheckoutProvider;
