import React, {useState, useRef, useMemo, useCallback, useEffect} from 'react'
import PropTypes from 'prop-types'
import {
    getPageCount,
    getPageData,
    getIsExpandable,
    makeTableHeaders,
    sortHoldings,
    makeSetPortfolio,
    // makeGetEffectOnSharpe,
} from './helpers'
import {SUBSCRIPTION_FREE_SECURITY_TYPES} from 'store/config'
import {tabs, rowTemplates, sortOptions} from './constants'
import {withPagination} from 'react-uikit/table'
import BEMModule from 'utils/bem'
import modalTypes from 'containers/modal-manager/modal-types'
import securityTypes from 'common-fe/constants/security-types'
import styles from './styles.scss'

import Accordion from 'react-uikit/accordion'
// import BodyTemplate from './partials/body-template'
import EmptyHoldingsRow from './partials/empty-holdings-row'
import Header from './partials/header'
import ListHeader from 'components/list-header'
import Overlay from './partials/overlay'
import TableTabs from 'components/table-tabs'

const Table = withPagination(Accordion)
const bem = new BEMModule(styles)

// TODO: Sharpe Ratio analysis feature is broken

const PortfolioHoldingsTable = ({
    className,
    exportData,
    // getSharpeTimeseries,
    isPublic,
    policy,
    portfolio,
    rowsPerPage,
    securities,
    showModal,
}) => {
    // Accordion Ref ===========================================================
    const accordionRef = useRef()
    const collapseAll = useCallback(() => {
        accordionRef?.current?.outerTableRef?.current?.closeAll()
    }, [accordionRef.current])

    // State ===================================================================
    const [holdings, setHoldings] = useState({})
    const [pageData, setPageData] = useState([])
    const [pageIndex, setPageIndex] = useState(1)
    const [sortOrder, setSortOrder] = useState(sortOptions[1].value) // 'DESC'
    const [tabData, setTabData] = useState([])
    const [tabIndex, setTabIndex] = useState(0)

    const overlayIsShowingInitialState = useMemo(
        () =>
            tabs.reduce((state, {value}) => {
                // Iterate through each tab to determine whether an overlay
                // should be displayed
                state[value] =
                    !policy.isSubscriptionActive &&
                    !SUBSCRIPTION_FREE_SECURITY_TYPES.includes(value)
                return state
            }, {}),
        [policy.isSubscriptionActive]
    )
    const [overlayIsShowing, setOverlayIsShowing] = useState(
        overlayIsShowingInitialState
    )

    // Table Config ============================================================
    const tab = tabs[tabIndex]
    const isEmpty = pageData.length === 0
    const isOverlayShowing = !isPublic && overlayIsShowing[tab.value]
    const RowTemplate = rowTemplates[tab.value]

    const tableHeaders = useMemo(() => makeTableHeaders({tab, isPublic}), [
        tabIndex,
        isPublic,
    ])

    // TODO: Sharpe Ratio analysis feature is broken
    const isExpandable = useMemo(() => getIsExpandable({tab, isPublic}), [
        tabIndex,
        isPublic,
    ])

    const onExchange = useCallback(
        () => showModal?.({type: modalTypes.MODAL_CURRENCY_EXCHANGE}),
        [showModal]
    )

    const onExercise = useCallback(
        ({security}) =>
            showModal?.({
                securityId: security.id,
                underlyingSecurityId: security.underlyingSecurityId,
                type: modalTypes.MODAL_OPTION_EXERCISE,
            }),
        [showModal]
    )

    const onTrade = useCallback(
        ({security}) =>
            showModal?.({
                securityId: security.id,
                shouldSubscribe: true,
                type: modalTypes.MODAL_ORDER,
            }),
        [showModal]
    )

    const rowProps = {onExchange, onExercise, onTrade}

    const setTab = useCallback(
        ({index}) => {
            const tab = tabs[index].value
            const tabData = sortHoldings({data: holdings[tab], sortOrder})
            const pageData = getPageData({
                data: tabData,
                pageIndex: 1,
                rowsPerPage,
            })

            collapseAll()
            setPageData(pageData)
            setPageIndex(1)
            setTabData(tabData)
            setTabIndex(index)
        },
        [holdings, rowsPerPage, sortOrder]
    )

    const updatePageIndex = useCallback(
        (newPageIndex) => {
            if (pageIndex === newPageIndex) {
                return
            }
            const pageData = getPageData({
                data: tabData,
                pageIndex: newPageIndex,
                rowsPerPage,
            })

            collapseAll()
            setPageData(pageData)
            setPageIndex(newPageIndex)
        },
        [holdings, tabIndex, pageIndex, rowsPerPage]
    )

    const pageCount = useMemo(
        () => getPageCount({total: tabData.length, rowsPerPage}),
        [tabData.length]
    )

    // const itemOpen = (index) => {
    //     // eslint-disable-line
    //     // // TODO: Implement sturdier solution. Eg. make onItemOpen return its
    //     // // data, and not only index, so we can get the item’s id that way.
    //     // // Accordion gives a number based on the index of ALL of its children (including non accordion.item children ie. header row)
    //     // // therefore reducing the index by one to get the proper index
    //     // const dataIndex = index - 1
    //     // const securityId = pageData[dataIndex].id
    //     // getSharpeTimeseries?.(securityId)
    // }

    // Overlay =================================================================
    const dismissOverlay = useCallback(() => {
        const currentTab = tabs[tabIndex]
        const isShowing = overlayIsShowing[tab.value]
        isShowing &&
            setOverlayIsShowing({
                ...overlayIsShowing,
                [currentTab.value]: false,
            })
    }, [])

    // Data Handling ===========================================================
    const setPortfolio = useMemo(
        () =>
            makeSetPortfolio({
                setHoldings,
                setPageData,
                setPageIndex,
                setSortOrder,
                setTabData,
                setTabIndex,
                collapseAll,
            }),
        []
    )

    // (1) If the portfolio has changed completely, update everything.
    useEffect(() => {
        setPortfolio({portfolio, tabIndex: 0, rowsPerPage})
    }, [portfolio.id])

    // (2) Otherwise, we can assume that the holdings data has changed,
    // and we can update the portfolio data only.
    useEffect(() => {
        setPortfolio({
            portfolio,
            pageIndex,
            sortOrder,
            tabIndex,
            rowsPerPage,
        })
    }, [portfolio.fetchedAt])

    // TODO: Sharpe Ratio analysis feature is broken
    //   const getEffectOnSharpe = makeGetEffectOnSharpe({
    //       sharpeTimeseriesCollection,
    //       portfolio,
    //   })

    // useEffect(() => {
    //     if (holdings) {
    //         const tab = tabs[tabIndex].value
    //         const tabData = sortHoldings({data: holdings?.[tab], sortOrder})

    //         setTabData(tabData)
    //     }
    // }, [holdings, tabIndex])

    // Styles ==================================================================
    const classes = bem.classNames('c-portfolio-holdings-table', className, {
        data: !isEmpty,
    })
    const tableClasses = bem.classNames('c-portfolio-holdings-table__table', {
        empty: isEmpty,
        'overlay-showing': isOverlayShowing,
    })
    const tableRowClasses = bem.classNames(
        'c-portfolio-holdings-table__table-row',
        {
            public: isPublic,
            empty: isEmpty,
            isExpandable: false,
            option: tab.value === securityTypes.OPTION.value,
            cash: tab.value === securityTypes.CASH.value,
        }
    )
    const tableRowHeaderClasses = bem.classNames(
        'c-portfolio-holdings-table__table-row-header',
        {isExpandable}
    )

    const tableHeaderClasses = bem.classNames(
        'c-portfolio-holdings-table__table-header',
        {
            public: isPublic,
            bond: tab.value === securityTypes.BOND.value,
            option: tab.value === securityTypes.OPTION.value,
            cash: tab.value === securityTypes.CASH.value,
            stock:
                tab.value === securityTypes.EQUITY.value ||
                tab.value === securityTypes.FUND.value,
        }
    )
    const paginationClasses = bem.classNames(
        'c-portfolio-holdings-table__pagination'
    )

    // Render ==================================================================
    return (
        <div className={classes}>
            <Header isPublic={isPublic} exportData={exportData} />
            <TableTabs tabIndex={tabIndex} tabs={tabs} setTab={setTab} />
            <Table
                className={tableClasses}
                currentPage={pageIndex}
                // disabled={!isExpandable}
                // multiSelect
                pageCount={pageCount}
                paginationClassName={paginationClasses}
                ref={accordionRef}
                scrollToTopOnPageChange
                // onItemOpen={itemOpen}
                onPageChange={updatePageIndex}
            >
                <ListHeader className={tableHeaderClasses}>
                    {tableHeaders.map(
                        (item, index) =>
                            item && (
                                <ListHeader.Item
                                    key={`portfolio-holdings-header-item-${index}`}
                                    {...item}
                                />
                            )
                    )}
                </ListHeader>

                {isEmpty ? (
                    <Accordion.Item
                        isPublic={isPublic}
                        className={tableRowClasses}
                        headerTemplate={EmptyHoldingsRow}
                        key={`empty-holdings`}
                        policy={policy}
                        securityType={tabs[tabIndex]}
                    />
                ) : (
                    pageData.map((security) => (
                        <Accordion.Item
                            className={tableRowClasses}
                            data={security}
                            headerClassName={tableRowHeaderClasses}
                            headerTemplate={RowTemplate}
                            isPublic={isPublic}
                            key={`holdings-${security.id}`}
                            policy={policy}
                            underlyingSecurity={
                                security.underlyingSecurityId
                                    ? securities[security.underlyingSecurityId]
                                    : null
                            }
                            {...rowProps}
                        >
                            {/* {!isPublic ? (
                                <BodyTemplate
                                    security={security}
                                    effectOnSharpe={getEffectOnSharpe(
                                        security.id
                                    )}
                                />
                            ) : null} */}
                            <div />
                        </Accordion.Item>
                    ))
                )}
                <Overlay
                    isShowing={isOverlayShowing}
                    securityType={tab.value}
                    onDismiss={dismissOverlay}
                />
            </Table>
        </div>
    )
}

PortfolioHoldingsTable.defaultProps = {
    rowsPerPage: 10,
}

PortfolioHoldingsTable.propTypes = {
    policy: PropTypes.object.isRequired,
    portfolio: PropTypes.shape({
        id: PropTypes.string,
        fetchedAt: PropTypes.oneOfType([
            PropTypes.string,
            PropTypes.instanceOf(Date),
        ]),
        holdings: PropTypes.shape({
            bonds: PropTypes.array,
            cash: PropTypes.array,
            count: PropTypes.shape({
                total: PropTypes.number,
            }),
            equities: PropTypes.array,
            funds: PropTypes.array,
            options: PropTypes.array,
        }),
    }).isRequired,
    className: PropTypes.string,
    exportData: PropTypes.func,
    getSharpeTimeseries: PropTypes.func,
    isPublic: PropTypes.bool,
    rowsPerPage: PropTypes.number,
    securities: PropTypes.object,
    sharpeTimeseriesCollection: PropTypes.object,
    showModal: PropTypes.func,
}

export default PortfolioHoldingsTable
