import React from 'react'
import {formatPortfolio} from 'store/helpers'
import {getHolding, getHoldingsBySecurityType} from 'utils/portfolio'
import {getPriceBySecurityType, getAmountTradeable} from 'utils/security'
import {ORDER_TRADE_ACTION_OPPOSING} from 'global/hooks/use-day-trading'
import {PoseGroup} from 'react-pose'
import {renderLargeNumber, renderWithCurrency} from 'common-fe/utils/render'
import {validateInput} from 'common-fe/utils/validation'
import Debug from 'common-fe/utils/debug'
import FormError, {reason} from 'common-fe/utils/form-error'
import inputNames from 'common-fe/constants/input-names'
import LogRocket from 'logrocket'
import modalTypes from 'containers/modal-manager/modal-types'
import moment from 'moment'
import orderActions from 'common-fe/constants/order-actions'
import orderExpiry from 'common-fe/constants/order-expiry'
import orderTypes from 'common-fe/constants/order-types'
import PortfolioClient from 'global/clients/portfolio'
import PropTypes from 'prop-types'
import securityTypes from 'common-fe/constants/security-types'

import {
    LONG,
    SHORT,
    START,
    orderActionOptions,
} from 'global/constants/order-actions'

import AnimateEnterExit from './partials/animate-enter-exit'
import Form from 'react-uikit/form'
import Icon from 'react-uikit/icon'
import Layout from 'react-uikit/layout'
import Loading from './partials/loading'
import OrderActionControl from 'components/order/action-control'
import OrderAlgorithm from 'components/order/algorithm'
import OrderExpiration from './partials/order-expiration'
import SelectInput from 'react-uikit/select-input'
import SubmitButton from './partials/submit-button'
import TextInput from 'react-uikit/input-text'
import Warning from './partials/warning'

import BEMModule from 'utils/bem'
import styles from './styles.scss'
const bem = new BEMModule(styles)

const TODAY = moment().endOf('day')
const IN_30_DAYS = TODAY.clone().add(29, 'days') // this will be 30 days if we include today

class OrderForm extends React.Component {
    // STATIC PROPERTIES =======================================================
    static formName = 'security-order'

    static orderTypes = [
        orderTypes.MARKET,
        orderTypes.LIMIT,
        orderTypes.STOP,
        orderTypes.STOP_LIMIT,
    ]

    /**
     *  Order Actions:
     *  (1) If the user doesn’t own current security, they should be able to BUY or SHORT.
     *  (2) If they already own the security, they can either BUY more or SELL the shares.
     *  (3) If the user has SHORT’ed the security, they should be able to either COVER the
     *  short or SHORT more shares.
     *
     *  @return  Array  e.g.[orderActions.BUY, orderActions.SHORT]
     */
    static getActionItems = (portfolio = {}, security = {}) => {
        const {holdings: securities} = portfolio
        const {id: securityId, type: securityType} = security
        const holdings = getHoldingsBySecurityType({securities}, securityType)

        // (1) Set to default: START
        let position = START

        if (holdings && holdings.length > 0) {
            // (2) Find all securities held with that id
            const matchedSecurities = holdings.filter(
                (security) => security.id === securityId
            )
            const isShort = (security) => security.position === SHORT
            const isLong = (security) => security.position === LONG

            // (3) Find if any are in LONG position
            position = matchedSecurities.some(isLong) ? LONG : position

            // (4) If the portfolio isn’t LONG, check if it is SHORT on the security
            if (position !== LONG && matchedSecurities.some(isShort)) {
                position = SHORT
            }
        }

        return orderActionOptions[position]
    }

    /**
     *  Returns the quantity available for trade based on the order action
     *  security, and portfolio.
     *  @return  Number  e.g. 9900
     */
    static getAmountTradeable = (security, portfolio, orderAction) => {
        const {id: securityId, type: securityType} = security
        const {holdings: securities} = portfolio
        const amountOutstanding = getAmountTradeable(security)
        const holdings = getHoldingsBySecurityType({securities}, securityType)
        const quantity = Math.abs(getHolding({holdings, securityId}).quantity)
        const openingActions = [
            orderActions.BUY.value,
            orderActions.SHORT.value,
        ]

        // check if the order action is a buy or a short and calculate the remaining securities available for purchase from the market
        if (openingActions.includes(orderAction)) {
            return amountOutstanding
                ? Math.max(0, amountOutstanding - quantity)
                : undefined // Removes the limit if amountOutstanding not available
        } else {
            // otherwise return the amount of securities held in the portfolio
            return quantity
        }
    }

    static defaultState = {
        data: {
            [inputNames.ORDER_ACTION]: {
                activeIndex: 0,
                items: [],
            },
            [inputNames.EXPIRATION]: [TODAY.toDate()],
            [inputNames.EXPIRY_TYPE]: orderExpiry.DAY,
            [inputNames.LIMIT_PRICE]: '',
            [inputNames.ORDER_QUANTITY]: '',
            [inputNames.ORDER_TYPE]: orderTypes.MARKET,
            [inputNames.STOP_PRICE]: '',
        },
        error: {},
    }

    // STATE ===================================================================
    state = {
        dayTrading: {
            isLoading: false,
            errors: [],
        },
    }

    // LIFECYCLE ===============================================================
    componentDidMount() {
        const {
            data: {
                [inputNames.ORDER_TYPE]: {value: orderType},
            },
            getAllCurrencies,
            getPortfolio,
            getSecurity,
            isCollapsed,
            orderAction,
            portfolio,
            security,
            setCollapsed,
        } = this.props
        const {id: portfolioId} = portfolio
        const updateOrderActions = (portfolio, security) =>
            this.change({
                name: inputNames.ORDER_ACTION,
                value: {
                    // We don't destructure `data` in the enclosed function scope
                    // because we want to use the most up-to-date reference i.e. this.props.data
                    activeIndex: this.props.data[inputNames.ORDER_ACTION]
                        .activeIndex,
                    items: OrderForm.getActionItems(portfolio, security),
                },
            })

        // Need to update all currency quotes to give the best estimates for fees
        getAllCurrencies && getAllCurrencies({overrideLoader: true})

        // nextOpen/nextClose dates only return from single security quotes
        getSecurity &&
            getSecurity({securityId: security.id}, {overrideLoader: true})

        // Get most up-to-date portfolio information in order to determine holding
        // position and available security
        !orderAction &&
            getPortfolio &&
            getPortfolio({portfolioId})
                .then((portfolio) => {
                    // Because there is a 5 second limit between getPortfolio requests, holdings may already be an object
                    // instead of an array
                    const formattedPortfolio = !Array.isArray(
                        portfolio.holdings
                    )
                        ? portfolio
                        : formatPortfolio({portfolio})
                    return updateOrderActions(formattedPortfolio, security)
                })
                .catch((err) =>
                    Debug.warn('WARN: Failed to fetch portfolio', err)
                )

        // We want to reset the collapsed state of the modal if needed
        const shouldCollapse = orderType !== orderTypes.MARKET.value

        shouldCollapse !== isCollapsed &&
            setCollapsed &&
            setCollapsed(shouldCollapse)

        this.getIsRestricted()
    }

    componentDidUpdate(prevProps) {
        const {data, security, onQuantityChange} = this.props
        const {security: prevSecurity} = prevProps
        const {items, activeIndex} = prevProps.data[inputNames.ORDER_ACTION]
        const prevOrderAction =
            items?.length > 0 ? items[activeIndex].value : null

        if (
            prevOrderAction !== this.orderAction ||
            prevSecurity?.previousOpen !== security?.previousOpen
        ) {
            this.getIsRestricted()
        }

        onQuantityChange?.({
            [inputNames.ORDER_ACTION]: this.orderAction,
            [inputNames.ORDER_QUANTITY]: data?.[inputNames.ORDER_QUANTITY],
            orderActionOptionsItemIndex:
                data?.[inputNames.ORDER_ACTION].activeIndex,
            estimatedPrice: this.estimatedOrderValue,
        })
    }

    // DAY TRADING =============================================================
    getIsRestricted = () => {
        const {portfolio, security} = this.props
        if (!this.orderAction || !security?.previousOpen) {
            return
        }

        const restrictedAction = ORDER_TRADE_ACTION_OPPOSING[this.orderAction]
        if (this.state.dayTrading.hasOwnProperty(this.orderAction)) {
            return
        }

        this.setState({
            dayTrading: {
                ...this.state.dayTrading,
                isLoading: true,
            },
        })

        // Only want to limit day trading when the market is open
        // Don't need to check last order if the market is closed
        if (new Date() > new Date(security.nextClose)) {
            this.setState({
                dayTrading: {
                    ...this.state.dayTrading,
                    [this.orderAction]: false,
                    isLoading: false,
                },
            })
        } else {
            const payload = {
                portfolioId: portfolio.id,
                securityId: security.id,
                startDate: security.previousOpen,
                tradeAction: restrictedAction,
            }

            PortfolioClient.getAllOrders(payload)
                .then((response) => {
                    if (response.length > 0) {
                        this.setState({
                            dayTrading: {
                                ...this.state.dayTrading,
                                [this.orderAction]: true,
                                isLoading: false,
                            },
                        })
                    } else {
                        this.setState({
                            dayTrading: {
                                ...this.state.dayTrading,
                                [this.orderAction]: false,
                                isLoading: false,
                            },
                        })
                    }
                })
                .catch((errors) => {
                    this.setState({
                        dayTrading: {
                            ...this.state.dayTrading,
                            isLoading: false,
                            errors,
                        },
                    })
                })
        }
    }

    // FORM ====================================================================
    get initialState() {
        const {
            orderActionOptionsItemIndex = 0,
            orderQuantity,
            portfolio,
            security,
        } = this.props

        return {
            data: {
                ...OrderForm.defaultState.data,
                [inputNames.ORDER_QUANTITY]:
                    orderQuantity ||
                    OrderForm.defaultState.data[inputNames.ORDER_QUANTITY],
                [inputNames.ORDER_ACTION]: {
                    activeIndex: orderActionOptionsItemIndex,
                    items: OrderForm.getActionItems(portfolio, security),
                },
            },
            error: {...OrderForm.defaultState.error},
        }
    }

    change = ({name, value}) => {
        const {data, portfolio, security, onChange} = this.props

        const payload = {[name]: value}

        switch (name) {
            case inputNames.ORDER_ACTION: {
                // Whenever the order action updates, we need to validate the
                // order quantity so that it does not exceed the amount tradeable
                const orderQuantity = data[inputNames.ORDER_QUANTITY]
                if (!orderQuantity) {
                    break
                }

                payload[inputNames.ORDER_QUANTITY] = Math.min(
                    orderQuantity,
                    OrderForm.getAmountTradeable(
                        security,
                        portfolio,
                        value.items[value.activeIndex]
                    )
                )
                break
            }
        }

        onChange && onChange(payload)
    }

    update = ({name, value}) => {
        const {isCollapsed, setCollapsed, onChange} = this.props

        const payload = {[name]: value}

        switch (name) {
            case inputNames.ORDER_TYPE: {
                const shouldCollapse = value.value !== orderTypes.MARKET.value

                shouldCollapse !== isCollapsed &&
                    setCollapsed &&
                    setCollapsed(shouldCollapse)
                break
            }

            case inputNames.ORDER_QUANTITY:
                payload[name] = Math.floor(value)
                break

            case inputNames.EXPIRY_TYPE: {
                if (value.value === orderExpiry.DAY.value) {
                    payload[inputNames.EXPIRATION] = [TODAY.toDate()]
                    break
                }

                payload[inputNames.EXPIRATION] = [IN_30_DAYS.toDate()]
                break
            }

            case inputNames.LIMIT_PRICE:
            case inputNames.STOP_PRICE:
                payload[name] = isNaN(value) ? '' : Number(value).toFixed(2)
                break
        }

        onChange && onChange(payload)
    }

    validate = ({name, value, isRequired}) => {
        let error = validateInput({name, value, isRequired})

        switch (name) {
            case inputNames.EXPIRATION: {
                if (Array.isArray(value) && !value.length) {
                    error = isRequired ? reason.FIELD_REQUIRED_ERR : null
                }
                break
            }

            case inputNames.ORDER_QUANTITY: {
                if (error) {
                    break
                }

                error = value <= 0 ? reason.VALUE_NOT_POSITIVE_ERR : null

                if (value > this.amountTradeable) {
                    error = `${
                        reason.VALUE_GREATER_THAN_ALLOWED_ERR
                    } ${renderLargeNumber(this.amountTradeable)}`
                }

                break
            }

            case inputNames.LIMIT_PRICE:
            case inputNames.STOP_PRICE: {
                if (error) {
                    break
                }

                if (value > 0) {
                    break
                }

                const {
                    data: {
                        [inputNames.ORDER_TYPE]: {value: orderType},
                    },
                } = this.props

                if (
                    orderType === orderTypes.STOP_LIMIT.value || // stop & limit price must be >= 0
                    (orderType === orderTypes.LIMIT.value &&
                        name === inputNames.LIMIT_PRICE) || // limit price must be >= 0
                    (orderType === orderTypes.STOP.value &&
                        name === inputNames.STOP_PRICE) // stop price must be >= 0
                ) {
                    error = reason.VALUE_NOT_POSITIVE_ERR
                    break
                }

                error = null
                break
            }
        }

        return error
    }

    submit = ({
        [inputNames.ORDER_ACTION]: {activeIndex, items: orderActions},
        [inputNames.ORDER_QUANTITY]: quantity,
        [inputNames.EXPIRATION]: [expiration],
        [inputNames.LIMIT_PRICE]: limitPrice,
        [inputNames.STOP_PRICE]: stopPrice,
        [inputNames.ORDER_TYPE]: {value: orderType},
    }) => {
        const {
            placeOrder,
            portfolio: {id: portfolioId},
            showModal,
            security: {id: securityId, nextClose},
            onError,
            onSubmit,
        } = this.props

        const nextCloseMoment = moment(nextClose)
        const expirationMoment = moment(expiration)

        const expirationDate = moment
            .max(nextCloseMoment, expirationMoment)
            .clone()
            .endOf('day')
            .format()

        const payload = {
            expiration: expirationDate,
            limitPrice,
            orderType,
            portfolioId,
            quantity,
            securityId,
            stopPrice,
            tradeAction: orderActions[activeIndex].value,
        }

        // Remove not-needed keys props
        switch (orderType) {
            case orderTypes.MARKET.value:
                delete payload.limitPrice
                delete payload.stopPrice
                delete payload.expiration
                break

            case orderTypes.LIMIT.value:
                delete payload.stopPrice
                break

            case orderTypes.STOP.value:
                delete payload.limitPrice
                break
        }

        placeOrder?.(payload)
            .then((order) => {
                onSubmit?.(payload).then(() => {
                    showModal?.({type: modalTypes.MODAL_TRADE_RATIONALE, order})
                })
            })
            .catch((err) => {
                LogRocket.captureException(err)

                if (
                    (!err?.inlineErrors?.length && !err?.generalErrors) ||
                    !onError
                ) {
                    return
                }

                const error = new FormError(
                    Object.keys(OrderForm.defaultState.data),
                    err.inlineErrors,
                    {[OrderForm.name]: err.generalErrors}
                )

                onError?.(error)
            })
    }

    // ORDER ===================================================================
    /**
     *  Returns Current Order Action, one of 'common-fe/constants/order-actions'
     *  @return  String  'BUY' | 'SELL' | 'SHORT' | 'COVER'
     */
    get orderAction() {
        const {items, activeIndex} = this.props.data[inputNames.ORDER_ACTION]

        return items && items.length > 0 ? items[activeIndex].value : null
    }

    /**
     *  Amount Tradeable: User should be able to place an order only for an
     *  amount available for the security, either on the market to BUY/SHORT or
     *  in their portfolio to SELL/SHORT.
     *  @return  Number  e.g. 9900
     */
    get amountTradeable() {
        const {security, portfolio} = this.props

        return OrderForm.getAmountTradeable(
            security,
            portfolio,
            this.orderAction
        )
    }

    /**
     *  Estimated Price: The price is estimated based on Order Action and
     *  Type and its parameters.
     *  @return  Number  e.g. 22.04
     */
    get estimatedPrice() {
        const {
            [inputNames.LIMIT_PRICE]: limitPrice,
            [inputNames.ORDER_TYPE]: {value: orderType},
            [inputNames.STOP_PRICE]: stopPrice,
        } = this.props.data

        switch (orderType) {
            case orderTypes.LIMIT.value:
            case orderTypes.STOP_LIMIT.value:
                return limitPrice

            case orderTypes.STOP.value:
                return stopPrice

            case orderTypes.MARKET.value:
            default:
                return getPriceBySecurityType(
                    this.orderAction,
                    this.props.security
                )
        }
    }

    /**
     *  Accrued Interest: Interest amount owed to seller
     *  @return  Number  e.g. 22.04
     */
    get accruedInterest() {
        const {
            security: {accruedInterest, parAmount, type},
        } = this.props

        if (securityTypes.BOND.value !== type) {
            return 0
        }

        return (accruedInterest * parAmount) / 100
    }

    /**
     *  Order fee for order type
     *  @return  Number  e.g. 22.04
     */
    get orderFee() {
        const {
            currencies,
            data: {[inputNames.ORDER_QUANTITY]: orderQuantity},
            security: {currency: transactionCurrency},
        } = this.props

        const quantity = isNaN(orderQuantity) ? 0 : orderQuantity
        const {
            [transactionCurrency]: toCurrency,
            USD: fromCurrency,
        } = currencies
        const feeUSD = 0.00025 * this.estimatedPrice * quantity

        // If the security's currency is in USD, then use the defined fees in
        // orderFees as they are defined in USD as well.
        if (transactionCurrency === 'USD' || !fromCurrency || !toCurrency) {
            return feeUSD
        }

        // Calculate the estimate cost of the fees in the same currency as the security
        const exchangeRate = toCurrency.currentPrice / fromCurrency.currentPrice
        return feeUSD * exchangeRate
    }

    /**
     *  Estimated Order Value
     *  @return  Number  e.g. 22.04
     */
    get estimatedOrderValue() {
        const {[inputNames.ORDER_QUANTITY]: orderQuantity} = this.props.data
        const quantity = isNaN(orderQuantity) ? 0 : orderQuantity
        const estimatedPrice = this.estimatedPrice
        const accruedInterest = this.accruedInterest

        // Get estimated price based on security type and order action
        return isNaN(estimatedPrice)
            ? ''
            : quantity * (estimatedPrice + accruedInterest) + this.orderFee
    }

    /**
     *  Order Types Allowed: Currently, only Stocks and ETFs can use
     *  Order Types other than Market.
     *  @return  Boolean
     */
    get isOrderTypesAllowed() {
        const {security} = this.props

        return [
            securityTypes.FUND.value,
            securityTypes.EQUITY.value,
            securityTypes.OPTION.value,
        ].includes(security.type)
    }

    /**
     *  Is Advanced Order Type: Any order type, apart from ‘Market’, is considered
     *  advance. Advanced order types require additional tempates.
     *  @return  Boolean
     */
    get isAdvancedOrderType() {
        const {value: orderType} = this.props.data[inputNames.ORDER_TYPE]
        return orderType && orderType !== orderTypes.MARKET.value
    }

    render() {
        const {
            data,
            data: {
                [inputNames.ORDER_TYPE]: {value: orderType},
            },
            error,
            onError,
            security,
            portfolio = {},
        } = this.props
        const {currency, type} = security

        const restrictDayTrading = portfolio?.courseSection?.restrictDayTrading
            ? portfolio.courseSection.restrictDayTrading
            : false

        const isDayTrading = this.state.dayTrading[this.orderAction]
        const isAllowedToTrade =
            !restrictDayTrading ||
            (!isDayTrading && !this.state.dayTrading.isLoading)

        const isTypeBond = securityTypes.BOND.value === type
        const isValidEstimatedPrice =
            this.estimatedPrice > 0 || data[inputNames.ORDER_QUANTITY] >= 0
        const tooltipId = 'c-order-form__type-input'

        const orderFormButtonClasses = bem.classNames('c-order-form__button')
        const orderFormWrapperClasses = bem.classNames('c-order-form__wrapper')
        const orderFormActionInputClasses = bem.classNames(
            'c-order-form__action-input'
        )
        const orderFormLabelsClasses = bem.classNames('c-order-form__labels')
        const orderFormPriceValueClasses = bem.classNames(
            'c-order-form__price-value',
            {
                error: this.estimatedPrice <= 0,
            }
        )
        const orderFormResultValueClasses = bem.classNames(
            'c-order-form__result-value',
            {
                error: this.estimatedPrice <= 0,
            }
        )
        const orderFormHRuleClasses = bem.classNames('c-order-form__h-rule')
        const orderFormErrorClasses = bem.classNames(
            'c-order-form__error-message'
        )

        return (
            <Form
                data={data}
                error={error}
                name={OrderForm.formName}
                submitOnEnter
                validate={this.validate}
                onChange={this.change}
                onError={onError}
                onSubmit={this.submit}
                onUpdate={this.update}
            >
                <Form.Field
                    className={orderFormActionInputClasses}
                    name={inputNames.ORDER_ACTION}
                    render={OrderActionControl}
                />

                {restrictDayTrading && this.state.dayTrading.isLoading && (
                    <Loading />
                )}
                {restrictDayTrading && isDayTrading && (
                    <Warning portfolio={portfolio} security={security} />
                )}
                {isAllowedToTrade && (
                    <>
                        <Layout.Grid className={orderFormWrapperClasses}>
                            <Layout.Flex
                                className={orderFormLabelsClasses}
                                align="center"
                                justify="end"
                            >
                                Order Type
                            </Layout.Flex>
                            <div />
                            <div data-tip data-for={tooltipId}>
                                <Form.Field
                                    disabled={!this.isOrderTypesAllowed}
                                    name={inputNames.ORDER_TYPE}
                                    options={OrderForm.orderTypes}
                                    render={SelectInput}
                                    size="small"
                                />
                            </div>
                        </Layout.Grid>
                        <PoseGroup>
                            {this.isAdvancedOrderType && (
                                <AnimateEnterExit key="order-algorithm">
                                    <OrderAlgorithm
                                        orderType={orderType}
                                        orderAction={this.orderAction}
                                    />

                                    <OrderExpiration
                                        className={orderFormWrapperClasses}
                                        value={data[inputNames.EXPIRATION]}
                                        expiryType={
                                            data[inputNames.EXPIRY_TYPE].value
                                        }
                                        labelClassName={orderFormLabelsClasses}
                                        maxDate={IN_30_DAYS.toDate()}
                                        minDate={TODAY.toDate()}
                                    />
                                </AnimateEnterExit>
                            )}
                        </PoseGroup>

                        <Layout.Grid className={orderFormWrapperClasses}>
                            <Layout.Flex
                                className={orderFormLabelsClasses}
                                align="center"
                                justify="end"
                            >
                                Estimated Price
                            </Layout.Flex>
                            <div />
                            <Layout.Flex
                                className={orderFormPriceValueClasses}
                                align="center"
                                justify="end"
                            >
                                {isValidEstimatedPrice
                                    ? renderWithCurrency(
                                          this.estimatedPrice,
                                          currency,
                                          {largeNumber: true, decimal: 2}
                                      )
                                    : 'Unable to calculate'}
                            </Layout.Flex>

                            {isTypeBond && (
                                <React.Fragment>
                                    <Layout.Flex
                                        className={orderFormLabelsClasses}
                                        align="center"
                                        justify="end"
                                    >
                                        Accrued Interest
                                    </Layout.Flex>
                                    <Layout.Flex
                                        align="center"
                                        justify="center"
                                    >
                                        <Icon
                                            name="add"
                                            style={{maxWidth: '0.8rem'}}
                                        />
                                    </Layout.Flex>
                                    <Layout.Flex
                                        className={orderFormPriceValueClasses}
                                        align="center"
                                        justify="end"
                                        style={{borderBottom: '1px solid'}}
                                    >
                                        {renderWithCurrency(
                                            this.accruedInterest,
                                            currency,
                                            {largeNumber: true, decimal: 2}
                                        )}
                                    </Layout.Flex>
                                    <Layout.Flex
                                        className={orderFormLabelsClasses}
                                        align="center"
                                        justify="end"
                                    >
                                        Bond Price
                                    </Layout.Flex>
                                    <div />
                                    <Layout.Flex
                                        className={orderFormPriceValueClasses}
                                        align="center"
                                        justify="end"
                                    >
                                        {isValidEstimatedPrice
                                            ? renderWithCurrency(
                                                  this.accruedInterest +
                                                      this.estimatedPrice,
                                                  currency,
                                                  {
                                                      largeNumber: true,
                                                      decimal: 2,
                                                  }
                                              )
                                            : 'Unable to calculate'}
                                    </Layout.Flex>
                                </React.Fragment>
                            )}
                            <Layout.Flex
                                className={orderFormLabelsClasses}
                                align="center"
                                justify="end"
                            >
                                Quantity
                            </Layout.Flex>

                            <Layout.Flex align="center" justify="center">
                                <Icon
                                    name="add"
                                    style={{
                                        maxWidth: '0.8rem',
                                        transform: 'rotate(45deg)',
                                    }}
                                />
                            </Layout.Flex>

                            <Form.Field
                                min={0}
                                name={inputNames.ORDER_QUANTITY}
                                placeholder="0"
                                render={TextInput}
                                required
                                showLength={false}
                                size="small"
                                textAlign="right"
                                type="number"
                            />
                            <Layout.Flex
                                align="center"
                                style={{gridColumn: '1 / 4'}}
                            >
                                <hr className={orderFormHRuleClasses} />
                            </Layout.Flex>
                            <Layout.Flex
                                className={orderFormLabelsClasses}
                                align="center"
                                justify="end"
                            >
                                Transaction Fee
                            </Layout.Flex>
                            <div />
                            <Layout.Flex
                                className={orderFormPriceValueClasses}
                                align="center"
                                justify="end"
                            >
                                {renderWithCurrency(this.orderFee, currency, {
                                    largeNumber: true,
                                    decimal: 2,
                                })}
                            </Layout.Flex>
                            <Layout.Flex
                                className={orderFormLabelsClasses}
                                align="center"
                                justify="end"
                            >
                                Estimated Total
                            </Layout.Flex>
                            <div />
                            <Layout.Flex
                                className={orderFormResultValueClasses}
                                align="center"
                                justify="end"
                            >
                                {isValidEstimatedPrice
                                    ? renderWithCurrency(
                                          this.estimatedOrderValue,
                                          currency,
                                          {largeNumber: true, decimal: 2}
                                      )
                                    : 'Unable to calculate'}
                            </Layout.Flex>

                            {this.estimatedPrice <= 0 &&
                                data[inputNames.ORDER_QUANTITY] > 1 && (
                                    <div className={orderFormErrorClasses}>
                                        We are unable to estimate the price at
                                        this time. You may still place an order
                                        and we will make our best attempts to
                                        fulfill it.
                                    </div>
                                )}

                            {error[OrderForm.name] && (
                                <div className={orderFormErrorClasses}>
                                    {error[OrderForm.name].map(
                                        (error, index) => (
                                            <p key={index}>{error}</p>
                                        )
                                    )}
                                </div>
                            )}
                        </Layout.Grid>

                        <Form.SubmitTrigger
                            className={orderFormButtonClasses}
                            render={SubmitButton}
                        />
                    </>
                )}
            </Form>
        )
    }
}

OrderForm.propTypes = {
    currencies: PropTypes.object.isRequired,
    portfolio: PropTypes.object.isRequired,
    security: PropTypes.object.isRequired,
    data: PropTypes.object,
    error: PropTypes.object,
    getAllCurrencies: PropTypes.func,
    getPortfolio: PropTypes.func,
    getSecurity: PropTypes.func,
    isCollapsed: PropTypes.bool,
    orderAction: PropTypes.string,
    orderActionOptionsItemIndex: PropTypes.number,
    orderQuantity: PropTypes.number,
    placeOrder: PropTypes.func,
    setCollapsed: PropTypes.func,
    showModal: PropTypes.func,
    onChange: PropTypes.func,
    onError: PropTypes.func,
    onQuantityChange: PropTypes.func,
    onSubmit: PropTypes.func,
}

OrderForm.defaultProps = {
    data: {...OrderForm.defaultState.data},
    error: {...OrderForm.defaultState.error},
    valid: {...OrderForm.defaultState.valid},
}

export default OrderForm
