<filename>packages/ui/src/redux/selectors/ratesSelector.js
import { createSelector } from 'reselect';
import { parseNumberToLocale } from '../../helpers/numberFormatter';
import BigNumber from 'bignumber.js';
import {
  selectedInstrumentDecimalPlacesSelector,
  selectedInstrumentSelector,
} from './instrumentPositionSelectors';

import { buyValue } from '../../constants/sendOrder/orderEntryFormConstants';
import { getOrderFormInfoBrandSpecificSelector } from './buySellSelectors';
import { selectAccountFeeByType } from './userSelectors';
import { getBalanceWithProductSymbol } from 'helpers/productHelper';
import { formatNumberToLocale } from 'helpers/numberFormatter';
import {
  getOrderFee,
  getOrderPricePerUnit,
  isMakerOrTaker,
} from 'helpers/orderHelper';
import { getPriceForGetOrderFeeRequest } from 'helpers/recalculateOrderHelper';
import {
  makerFeeValue,
  takerFeeValue,
  takerValue,
} from 'constants/sendOrder/makerTakerConstants';

const isBuySideBuySellFormSelector = createSelector(
  [(state) => state.form.buySell],
  (formObj) => {
    return formObj ? formObj.values.side === buyValue : true;
  }
);

export const getGoldRatesSelector = createSelector(
  [(state) => state],
  (state) => {
    const goldInstrument = state.instrument.instruments.find(
      (inst) => inst.Symbol === 'GOLDUSD'
    );

    const goldInstrumentId =
      goldInstrument && goldInstrument.InstrumentId
        ? goldInstrument.InstrumentId
        : 41;

    const inst = state.level1[goldInstrumentId];

    return {
      Bid: (inst && inst.BestBid) || 0,
      Ask: (inst && inst.BestOffer) || 0,
      isFetching: !inst,
    };
  }
);

export const getOrderInfoFormattedSelector = createSelector(
  [
    (state) => state,
    getOrderFormInfoBrandSpecificSelector,
    selectedInstrumentSelector,
    selectedInstrumentDecimalPlacesSelector,
    isBuySideBuySellFormSelector,
  ],
  (state, selectedValue, selectedInstrument, decimalPlaces, isBuySide) => {
    const quantity = selectedValue.quantity ? selectedValue.quantity : 0;
    const price = selectedValue.price ? selectedValue.price : 0;
    const limitPrice = selectedValue.limitPrice ? selectedValue.limitPrice : 0;
    const pricePerUnit = selectedValue.pricePerUnit
      ? selectedValue.pricePerUnit
      : 0;

    const { Product1Symbol, Product2Symbol } = selectedInstrument;
    const {
      form: { buySell: buySellForm = { values: { fee: {} } } },
      position,
    } = state;
    const { OrderFee = 0 } = buySellForm.values.fee;

    const selectedLevel1Data = state.level1[selectedInstrument.InstrumentId];

    const checkIsMakerOrTakerFee =
      isMakerOrTaker(
        buySellForm.values.side,
        getPriceForGetOrderFeeRequest(
          buySellForm.values.price,
          selectedLevel1Data
        ),
        selectedLevel1Data?.BestBid,
        selectedLevel1Data?.BestOffer,
        buySellForm.values.orderType
      ) === takerValue
        ? takerFeeValue
        : makerFeeValue;

    const feePercentage = selectAccountFeeByType(state, checkIsMakerOrTakerFee);

    const actualPrice = new BigNumber(price).minus(OrderFee);

    const actualQuantity =
      parseNumberToLocale(buySellForm.values.quantity) > 0
        ? new BigNumber(buySellForm.values.quantity).minus(OrderFee)
        : 0;

    return {
      quantity: formatNumberToLocale(quantity, decimalPlaces[Product1Symbol]),

      actualQuantity: formatNumberToLocale(
        actualQuantity,
        decimalPlaces[Product1Symbol]
      ),

      limitPrice,

      pricePerUnit: getBalanceWithProductSymbol(
        Product2Symbol,
        getOrderPricePerUnit(
          pricePerUnit,
          Product1Symbol,
          Product2Symbol,
          decimalPlaces,
          isBuySide
        ),
        true
      ),

      feePercentage: feePercentage,

      feeFormatted: getOrderFee(buySellForm, position.positions, 'end'),

      actualPrice: getBalanceWithProductSymbol(
        Product2Symbol,
        formatNumberToLocale(
          actualPrice,
          decimalPlaces[Product2Symbol],
          isBuySide ? BigNumber.ROUND_CEIL : BigNumber.ROUND_FLOOR
        ),
        true
      ),

      totalPrice: getBalanceWithProductSymbol(
        Product2Symbol,
        formatNumberToLocale(
          price,
          decimalPlaces[Product2Symbol],
          isBuySide ? BigNumber.ROUND_CEIL : BigNumber.ROUND_FLOOR
        ),
        true
      ),

      price: getBalanceWithProductSymbol(
        Product2Symbol,
        formatNumberToLocale(
          price,
          decimalPlaces[Product2Symbol],
          isBuySide ? BigNumber.ROUND_CEIL : BigNumber.ROUND_FLOOR
        ),
        true
      ),
    };
  }
);
