import { FC, useEffect, useRef, useState } from 'react';
import Wizard from '../../../../components/ui/Wizard/Wizard';
import { createStyles, makeStyles, Typography } from '@material-ui/core';
import CustomerAndOrderType, { CustomerInterface } from './content/CustomerAndOrderType';
import { getQuery } from 'mystique/hooks/getQuery';
import { FormFieldProps } from 'mystique/registry/FieldRegistry';
import { useData } from 'mystique/hooks/useData';
import BasketInformation from './content/BasketInformation';
import DeliveryTypes from './content/DeliveryTypes';
import { pushToast } from 'mystique/frame/pushToast';
import { useI18n } from 'mystique/hooks/useI18n';
import { v4 as uuidv4 } from 'uuid';
import { TemplateRegistry } from 'mystique/registry/TemplateRegistry';
import { DynamicAttribute } from 'mystique/components/DynamicValue';
import AddProductItems from '../../../../components/AddProductItems/AddProductItems';
import { useDefaultTariffValue } from '../../../../hooks/useDefaultTariffValue';
import { useActiveRetailer } from '../../../../hooks/useActiveRetailer';
import { MultiOrder, MultiOrderItem } from './content/MultiBasketCollection';
import { Location } from 'interfaces/locations';
import { getBaseLocations } from '../../../../queries/getBaseLocations';
import { CustomerAddress } from 'interfaces/address';
import { getDefaultCustomerAddress } from '../../../../queries/getDefaultCustomerAddress';
import { FulfilmentCCPlanInterface, FulfilmentHDPlanInterface } from 'interfaces/fulfilmentPlans';
import { createFulfilmentPlans } from '../../../../queries/createFulfilmentPlans';
import { CreateOrderContext } from './CreateOrderContext';
import _ from 'lodash';
import FinancialTransactions from './content/FinancialTransactions';
import { Product } from '../../../../components/AddProductItems/AddProductItemsModal';

export interface VirtualCatalogue {
  ref: string;
  type?: 'aggregate' | 'base';
}

const createOrderMutation = `
    mutation (
        $orderRef: String!, 
        $type: String!, 
        $retailerId: ID!, 
        $fulfilmentChoice: CreateFulfilmentChoiceWithOrderInput,
        $fulfilmentChoices: [CreateFulfilmentChoiceWithOrderInput],
        $customerId: ID!,
        $orderItems: [CreateOrderItemWithOrderInput]!
        $totalPrice: Float,
        $totalTaxPrice: Float,
        $attributes: [AttributeInput],
        $financialTransactions: [CreateFinancialTransactionWithOrderInput],
        ) {
        createOrder(input : {
            ref: $orderRef
            type: $type
            totalPrice: $totalPrice
            totalTaxPrice: $totalTaxPrice
            attributes: $attributes
            retailer: {
                id: $retailerId
            }
            fulfilmentChoice: $fulfilmentChoice
            fulfilmentChoices: $fulfilmentChoices
            customer: {
                id: $customerId
            }
            items: $orderItems
            financialTransactions: $financialTransactions
        }) {
            ref,
            id
        }
    }
`;

export interface CreateOrderInterface {
  products: OrderItem[];
  totalPrice: number;
  type: 'CC' | 'HD';
  customer: CustomerInterface;
  deliveryType: string;
  multiOrder?: MultiOrder;
  totalTaxPrice?: number;
  deliveryAddress?: CustomerAddress;
  pickupLocationRef?: string;
  fulfilmentPlanRef?: string;
  carrier?: string;
  fulfilmentOptionId?: string;
  summaryPage?: boolean;
  useMultiOrder?: boolean;
  financialTransactions: FinancialTransaction[];
}

export interface FinancialTransaction {
  ref: string;
  type: string;
  amount: number;
  currency: string;
  externalTransactionCode: string | null;
  externalTransactionId: string | null;
  cardType: string | null;
  paymentMethod: string;
  paymentProvider: string | null;
}

export interface OrderItem {
  ref: string;
  name: string;
  quantity: number;
  available: number;
  prices: {
    taxType?: string;
    currency: string;
    value: number;
  }[];
  price: number;
  taxPrice: number;
  taxType?: string;
  imageUrl?: string;
  originalPrice?: number;
  attributes?: DynamicAttribute[];
}

export const CreateOrder: FC<FormFieldProps<string>> = ({
  lastSubmit,
  onChange,
}) => {
  const {translate} = useI18n();

  const [createOrderInf, setCreateOrderInf] = useState<CreateOrderInterface>();
  const [defaultAddress, setDefaultAddress] =
    useState<CustomerAddress | undefined>();
  const [locations, setLocations] = useState<Location[]>([]);
  const [fulfilmentPlans, setFulfilmentPlans] = useState<
    FulfilmentHDPlanInterface[] | FulfilmentCCPlanInterface[]
  >([]);
  const orderRef = useRef('');

  const classes = useStyles();
  let creatingOrder = false;
  const data = useData();

  const activeRetailer = useActiveRetailer();

  const tariffValue = useDefaultTariffValue();

  const updateFieldForState = (value: unknown, property: string) => {
    setCreateOrderInf((prevState: any) => {
      const result =  prevState == undefined
        ? {[property]: value}
        : {...prevState, [property]: value};

      console.log("!!! RESULT  => ", result);
      return result;
    });
  };

  useEffect(() => {
    if (lastSubmit && !createOrderInf?.summaryPage) {
      pushToast(
        'error',
        translate('fc.se.field.create.order.not.complete.steps'),
        2000,
      );
    } else if (lastSubmit && createOrderInf?.summaryPage) {
      createOrder();
    }
  }, [lastSubmit]);

  useEffect(() => {
    if (createOrderInf && createOrderInf.summaryPage) {
      orderRef.current = `${
        createOrderInf.useMultiOrder ? 'MULTI' : createOrderInf.type
      }-${Date.now()}`;
      onChange(
        translate(
          'fc.se.field.create.order.successfully.created.order.message',
          {
            ref: orderRef.current,
            name: createOrderInf.customer.name,
          },
        ),
      );
    }
  }, [createOrderInf]);

  useEffect(() => {
    if (createOrderInf?.customer) {
      getDefaultCustomerAddress({
        customerName: createOrderInf.customer.name,
      }).then(setDefaultAddress);
      if (activeRetailer) {
        getBaseLocations({activeRetailer: activeRetailer}).then(setLocations);
      }
    }
  }, [createOrderInf?.customer, createOrderInf?.type]);

  useEffect(() => {
    const totalTaxPrice = parseFloat(
      ((createOrderInf?.totalPrice || 0) * tariffValue).toFixed(2),
    );
    updateFieldForState(totalTaxPrice, 'totalTaxPrice');
  }, [createOrderInf?.totalPrice]);

  const createOrder = () => {
    if (createOrderInf) {
      const mutVariables: any = {
        orderRef: orderRef.current,
        type: createOrderInf.useMultiOrder ? 'MULTI' : createOrderInf.type,
        retailerId: activeRetailer,
        customerId: createOrderInf.customer.id,
        totalPrice: createOrderInf.totalPrice,
        totalTaxPrice: createOrderInf.totalTaxPrice,
      };

      if (createOrderInf.useMultiOrder && createOrderInf.multiOrder) {
        const multiOrderItems: MultiOrderItem[] = _.cloneDeep(
          createOrderInf.multiOrder.orderItems,
        );

        const usageDeliveryAddress = multiOrderItems.reduce(
          (acc: any[], item) => {
            if (
              acc.filter(
                (accItem: any) =>
                  accItem.ref === item.deliveryAddressRef &&
                  accItem.deliveryType === item.deliveryType,
              ).length
            ) {
              return acc;
            }
            acc.push({
              ref: item.deliveryAddressRef,
              deliveryType: item.deliveryType,
            });

            return acc;
          },
          [],
        );

        const usagePickupLocation = multiOrderItems.reduce(
          (acc: any[], item) => {
            if (
              acc.filter(
                (accItem: any) =>
                  accItem.ref === item.pickupLocationRef &&
                  accItem.deliveryType === item.deliveryType,
              ).length
            ) {
              return acc;
            }
            acc.push({
              ref: item.pickupLocationRef,
              deliveryType: item.deliveryType,
            });

            return acc;
          },
          [],
        );

        const fulfilmentChoices = multiOrderItems
          .map((item) => {
            if (
              (item.orderItemType === 'HD' &&
                usageDeliveryAddress.filter(
                  (address) =>
                    item.deliveryAddressRef === address.ref &&
                    item.deliveryType === address.deliveryType,
                ).length) ||
              (item.orderItemType === 'CC' &&
                usagePickupLocation.filter(
                  (location) =>
                    item.pickupLocationRef === location.ref &&
                    item.deliveryType === location.deliveryType,
                ).length)
            ) {
              const ccFulfilmentRef = `Multi-cc-${Math.random() * 100}`;
              const hdFulfilmentRef = `Multi-hd-${Math.random() * 100}`;

              if (item.orderItemType === 'HD') {
                const fulfilAddress = usageDeliveryAddress.splice(
                  usageDeliveryAddress
                    .map((address) => `${address.ref} ${address.deliveryType}`)
                    .indexOf(`${item.deliveryAddressRef} ${item.deliveryType}`),
                  1,
                );
                addFulfilmentRefToOrderItems(
                  multiOrderItems,
                  fulfilAddress[0],
                  hdFulfilmentRef,
                );
              }

              if (item.orderItemType === 'CC') {
                const fulfilLocation = usagePickupLocation.splice(
                  usagePickupLocation
                    .map(
                      (location) => `${location.ref} ${location.deliveryType}`,
                    )
                    .indexOf(`${item.pickupLocationRef} ${item.deliveryType}`),
                  1,
                );
                addFulfilmentRefToOrderItems(
                  multiOrderItems,
                  fulfilLocation[0],
                  ccFulfilmentRef,
                );
              }

              const deliveryAddress =
                createOrderInf.multiOrder?.customerAddresses.find(
                  (address) => address.ref === item.deliveryAddressRef,
                );

              const newFulfilmentChoice: any = {
                ref:
                  item.orderItemType === 'HD'
                    ? hdFulfilmentRef
                    : ccFulfilmentRef,
                type: item.orderItemType,
                deliveryType: item.deliveryType,
                fulfilmentType:
                  item.orderItemType === 'HD' ? 'HD_PFDC' : 'CC_PFS',
                pickupLocationRef:
                  item.orderItemType === 'CC'
                    ? item.pickupLocationRef
                    : undefined,
                deliveryAddress:
                  item.orderItemType === 'HD'
                    ? {
                      ref: uuidv4(),
                      street: deliveryAddress?.street,
                      postcode: deliveryAddress?.postcode,
                      city: deliveryAddress?.city,
                      country: deliveryAddress?.country,
                      state: deliveryAddress?.state,
                      companyName: deliveryAddress?.companyName || '',
                      name: createOrderInf.customer.name,
                    }
                    : undefined,
              };

              return newFulfilmentChoice;
            }

            return undefined;
          })
          .filter((choice) => choice != undefined);

        mutVariables.fulfilmentChoices = fulfilmentChoices;
        mutVariables.orderItems = multiOrderItems.map((item) => {
          return {
            ref: item.ref,
            productRef: item.ref,
            productCatalogueRef: `MASTER:${activeRetailer}`, // TODO product catalogue ref (for example, DEFAULT or MASTER)
            quantity: item.quantity,
            paidPrice: item.price,
            currency: item.prices[0].currency,
            price: item.price,
            taxPrice: item.taxPrice,
            totalPrice: item.price * item.quantity,
            totalTaxPrice: item.taxPrice * item.quantity,
            fulfilmentChoiceRef: item.fulfilmentRef,
          };
        });
      } else {
        const fulfilmentChoice =
          createOrderInf.type === 'HD'
            ? {
              deliveryType: createOrderInf.deliveryType,
              fulfilmentType: 'HD_PFDC',
              deliveryAddress: {
                ref: uuidv4(),
                name: createOrderInf.customer.name,
                street:
                  createOrderInf.deliveryAddress?.street ||
                  defaultAddress?.street,
                city:
                  createOrderInf.deliveryAddress?.city ||
                  defaultAddress?.city,
                postcode:
                  createOrderInf.deliveryAddress?.postcode ||
                  defaultAddress?.postcode,
                country:
                  createOrderInf.deliveryAddress?.country ||
                  defaultAddress?.country,
                companyName:
                  createOrderInf.deliveryAddress?.companyName ||
                  defaultAddress?.companyName ||
                  '',
                state:
                  createOrderInf.deliveryAddress?.state ||
                  defaultAddress?.state ||
                  '',
              },
            }
            : {
              deliveryType: createOrderInf.deliveryType,
              fulfilmentType: 'CC_PFS',
              pickupLocationRef: createOrderInf.pickupLocationRef,
            };

        const attributes: any = [];

        if (createOrderInf.carrier) {
          attributes.push({
            name: 'CARRIER',
            type: 'STRING',
            value: createOrderInf.carrier,
          });
        }

        mutVariables.fulfilmentChoice = fulfilmentChoice;
        mutVariables.attributes = attributes;
        mutVariables.orderItems = createOrderInf.products.map((product) => {
          return {
            ref: product.ref,
            productRef: product.ref,
            productCatalogueRef: `MASTER:${activeRetailer}`, // TODO product catalogue ref (for example, DEFAULT or MASTER)
            quantity: product.quantity,
            paidPrice: product.price,
            currency: product.prices[0].currency,
            price: product.price,
            taxPrice: product.taxPrice,
            totalPrice:
              product.price * product.quantity,
            totalTaxPrice:
              product.taxPrice * product.quantity,
          };
        });
      }

      mutVariables.financialTransactions = createOrderInf.financialTransactions;
      if (createOrderInf.fulfilmentOptionId) {
        mutVariables.attributes = [
          ...(mutVariables.attributes || []),
          {
            'name': 'FULFILMENT_OPTION_ID',
            'type': 'STRING',
            'value': createOrderInf.fulfilmentOptionId,
          },
        ];
      }
      if (!creatingOrder) {
        creatingOrder = true;
        getQuery<any>(createOrderMutation, mutVariables)
          .then((resp: any) => {
            window.location.hash = TemplateRegistry.render(
              `#/orders/${resp.data.createOrder.id}/${activeRetailer}/${resp.data.createOrder.ref}`,
            );
          })
          .then(() => {
            pushToast(
              'success',
              translate('fc.se.field.create.order.success.created.order'),
              2000,
            );
          });
      }
    }
  };

  const addFulfilmentRefToOrderItems = (
    orderItems: MultiOrderItem[],
    fulfilment: any,
    fulfilmentRef: string,
  ) => {
    const orderItemsForFulfilmentRef = orderItems.filter((orderItem) => {
      if (orderItem.orderItemType === 'HD') {
        return (
          orderItem.deliveryType === fulfilment.deliveryType &&
          orderItem.deliveryAddressRef === fulfilment.ref
        );
      } else {
        return (
          orderItem.deliveryType === fulfilment.deliveryType &&
          orderItem.pickupLocationRef === fulfilment.ref
        );
      }
    });
    orderItemsForFulfilmentRef.forEach((orderItem) => {
      orderItem.fulfilmentRef = fulfilmentRef;
    });
  };

  const checkCustomerAndAddress = () => {
    return !(
      createOrderInf?.customer &&
      ((createOrderInf.type === 'CC' && createOrderInf.pickupLocationRef) ||
        (createOrderInf.type === 'HD' &&
          createOrderInf.deliveryAddress &&
          createOrderInf.deliveryAddress.postcode &&
          createOrderInf.deliveryAddress.street &&
          createOrderInf.deliveryAddress.country) ||
        (createOrderInf.type === 'HD' &&
          defaultAddress &&
          defaultAddress.postcode &&
          defaultAddress.street &&
          defaultAddress.country))
    );
  };

  const checkFinancialTransactions = () => {
    if (createOrderInf?.financialTransactions) {
      for (const financialTransaction of createOrderInf?.financialTransactions) {
        if (
          !financialTransaction.ref ||
          !financialTransaction.type ||
          financialTransaction.amount <= 0 ||
          isNaN(financialTransaction.amount) ||
          !financialTransaction.currency ||
          !financialTransaction.paymentMethod
        ) {
          return true;
        }
      }
    }
    return false;
  };

  function convertToProduct(variantProduct: any) {
    if (variantProduct) {
      const available = data.context.data?.searchVirtualInventory?.edges.reduce(
        (p: any, c: any) =>
          p +
          c.node.virtualPositions.reduce((p: any, c: any) => p + c.quantity, 0),
        0,
      );

      return {
        ref: variantProduct.ref,
        name: variantProduct.name,
        prices: variantProduct.prices,
        imageUrl: variantProduct.attributes?.byName.imageUrl,
        attributes: variantProduct.attributes,
        available: available,
      } as Product;
    }
    return undefined;
  }

  return (
    <CreateOrderContext.Provider
      value={{
        createOrderInf: createOrderInf,
        availableLocations: locations,
        customerAddresses: {
          customerName: createOrderInf?.customer,
          defaultAddress: defaultAddress,
        },
        setCreateOrderInf: setCreateOrderInf,
      }}
    >
      <Wizard
        title={translate('fc.se.field.create.order.title')}
        steps={[
          {
            required: true,
            title: translate('fc.se.field.create.order.first.step.title'),
            disabled: !createOrderInf?.products?.length,
            content: (
              <>
                <div className={classes.content}>
                  <AddProductItems
                    defaultProduct={convertToProduct(
                      data.context.data.variantProduct,
                    )}
                    products={createOrderInf?.products || []}
                    onChange={(value, property) => {
                      updateFieldForState(value, property);
                      updateFieldForState(undefined, 'multiOrder');
                    }}
                    price={createOrderInf?.totalPrice}
                    totalTaxPrice={createOrderInf?.totalTaxPrice}
                  />
                </div>
                <div className={classes.bottom}>
                  <Typography>
                    *{' '}
                    {translate(
                      'fc.se.field.create.order.bottom.required.label',
                    )}
                  </Typography>
                </div>
              </>
            ),
          },
          {
            required: true,
            title: translate('fc.se.field.create.order.second.step.title'),
            disabled: checkCustomerAndAddress(),
            content: (
              <>
                <div className={classes.content}>
                  {createOrderInf ? (
                    <CustomerAndOrderType
                      defaultCustomer={data.context.data.customerById?.ref}
                      onChange={updateFieldForState}
                    />
                  ) : null}
                </div>
                <div className={classes.bottom}>
                  <Typography>
                    *{' '}
                    {translate(
                      'fc.se.field.create.order.bottom.required.label',
                    )}
                  </Typography>
                </div>
              </>
            ),
            onNext: () => {
              setFulfilmentPlans([]);
              if (createOrderInf) {
                createFulfilmentPlans({
                  deliveryAddress:
                    createOrderInf?.deliveryAddress || defaultAddress,
                  pickupLocationRef: createOrderInf.pickupLocationRef,
                  orderType: createOrderInf?.type,
                  activeRetailer: activeRetailer,
                  products: createOrderInf?.products,
                }).then((value) => {
                  if (value) {
                    setFulfilmentPlans(value);
                    updateFieldForState(
                      value[0].fulfilmentOptionId,
                      'fulfilmentOptionId',
                    );
                  }
                });
              }
              updateFieldForState('STANDARD', 'deliveryType');
            },
          },
          {
            required: true,
            title: translate('fc.se.field.create.order.third.step.title'),
            disabled: !(createOrderInf?.useMultiOrder
              ? createOrderInf?.multiOrder?.orderItems.every(
                (item) =>
                  item.deliveryType &&
                  (item.orderItemType == 'CC'
                    ? item.pickupLocationRef
                    : item.deliveryAddressRef),
              )
              : createOrderInf?.deliveryType),
            content: (
              <>
                <div className={classes.content}>
                  {!!createOrderInf && (
                    <DeliveryTypes
                      onChange={updateFieldForState}
                      fulfilmentPlans={fulfilmentPlans}
                      fulfilmentPlanRef={createOrderInf.fulfilmentPlanRef}
                    />
                  )}
                </div>
                <div className={classes.bottom}>
                  <Typography>
                    *{' '}
                    {translate(
                      'fc.se.field.create.order.bottom.required.label',
                    )}
                  </Typography>
                </div>
              </>
            ),
          },
          {
            required: true,
            title: translate(
              'fc.se.field.create.order.fifth.step.financial.transaction.title',
            ),
            disabled: checkFinancialTransactions(),
            content: (
              <>
                <div className={classes.content}>
                  {createOrderInf ? (
                    <FinancialTransactions onChange={updateFieldForState} />
                  ) : null}
                </div>
                <div className={classes.bottom}>
                  <Typography>
                    *{' '}
                    {translate(
                      'fc.se.field.create.order.bottom.required.label',
                    )}
                  </Typography>
                </div>
              </>
            ),
          },
        ]}
        summary={{
          title: translate('fc.se.field.create.order.summary.title'),
          content: (
            <>
              <div className={classes.content}>
                {!!createOrderInf && (
                  <BasketInformation
                    products={createOrderInf.products}
                    orderType={createOrderInf.type}
                    onChange={updateFieldForState}
                    address={createOrderInf.deliveryAddress || defaultAddress}
                    locationRef={createOrderInf.pickupLocationRef}
                    deliveryType={createOrderInf.deliveryType}
                    price={createOrderInf.totalPrice}
                    totalTaxPrice={
                      createOrderInf.totalTaxPrice
                    }
                    useMultiOrder={createOrderInf.useMultiOrder}
                    multiOrder={createOrderInf.multiOrder}
                  />
                )}
              </div>
              <div className={classes.bottom}>
                <Typography>
                  *{' '}
                  {translate('fc.se.field.create.order.bottom.required.label')}
                </Typography>
              </div>
            </>
          ),
        }}
      />
    </CreateOrderContext.Provider>
  );
};

const useStyles = makeStyles(() =>
  createStyles({
    content: {
      minHeight: '50vh',
      paddingBottom: '20px',
      display: 'flex',
      flexDirection: 'column',
      gap: '15px',
      maxWidth: '350px',
      alignItems: 'flex-start',
    },
    bottom: {
      borderTop: '1px solid #D4D6D8',
      color: '#999999',
    },
  }),
);
