import React from 'react'
import PropTypes from 'prop-types'
import {toCamelCase} from 'common-fe/utils'
import {withPagination} from 'react-uikit/table'
import Accordion from 'react-uikit/accordion'
import Banner from 'components/banner'
import HeaderTemplate from 'components/table-row-heading'
import BEMModule from 'utils/bem'
import BodyTemplate from './partials/body-template'
import content from './content'
import metricIds from 'global/constants/metric-ids'
import rankingPeriods from 'global/constants/ranking-periods'
import styles from './styles.scss'

const bem = new BEMModule(styles)

const PaginatedAccordion = withPagination(Accordion)

class LeaderboardTable extends React.Component {
    accordion = React.createRef()
    header = React.createRef()
    rows = {}

    get hasRanking() {
        return this.props.list.length > 0
    }

    collapseAll = () => {
        this.accordion?.current?.outerTableRef?.current?.closeAll?.()
    }

    expandIndex = (index) => {
        this.accordion?.current?.outerTableRef?.current?.onOpen?.(index)
    }

    onPageChange = (page) => {
        this.collapseAll()
        this.props.setPage?.(page)
        this.header.current.scrollIntoView({
            behavior: 'smooth',
            block: 'center',
        })
    }

    getRank = (portfolioId) => {
        this.props.getRank?.({
            portfolioId,
            courseId: this.props.courseId,
            metricId: this.props.metricId,
            period: this.props.period,
        })
    }

    scrollToRow = (rowId) => {
        this.rows[rowId]?.current?.scrollIntoView({
            behavior: 'smooth',
            block: 'center',
        })
    }

    onRowExpanded = (index) => {
        const row = this.props.list[index]
        const portfolioId = row?.portfolio?.id
        const {
            getPortfolioSharpeTimeseries,
            getPublicPortfolio,
            period,
            portfolios = [],
            timeseries = {},
        } = this.props

        // When the row expands, we want to retrieve their historical data & rank
        // metrics to display in the accordion body
        if (!timeseries.hasOwnProperty(portfolioId)) {
            getPortfolioSharpeTimeseries?.({portfolioId, period})
        }
        if (!portfolios.some?.((id) => id === portfolioId)) {
            getPublicPortfolio?.({portfolioId}, {overrideLoader: true})
        }
        this.getRank(portfolioId)
        this.scrollToRow(portfolioId)
    }

    handleJumpToTop = () => this.onPageChange(1)

    renderStatusBanner = ({isLoading, hasErrors}) => {
        if (hasErrors) {
            const bannerIconClassNames = bem.classNames(
                'c-leaderboard-table__banner-icon'
            )
            return (
                <Banner warning>
                    <em className={bannerIconClassNames}>
                        <span role="img" aria-label="Shocked and scared">
                            😱
                        </span>{' '}
                    </em>
                    &nbsp;Something went wrong… Please, check again later.
                </Banner>
            )
        }

        if (isLoading) {
            return <Banner neutral>Loading...</Banner>
        }

        return <Banner neutral>There are no rankings to display.</Banner>
    }

    render() {
        const {
            currentPage = 1,
            hasErrors,
            isLoading,
            list,
            metricId,
            pageCount = 1,
            period,
            title,
            onAvatarClick,
        } = this.props

        const linksClassNames = bem.classNames('c-leaderboard-table__links')
        const linkClassNames = bem.classNames('c-leaderboard-table__link')
        const titleClassNames = bem.classNames('c-leaderboard-table__title')
        const headerClassNames = bem.classNames('c-leaderboard-table__header')
        const paginationClassNames = bem.classNames(
            'c-leaderboard-table__pagination'
        )
        const metricKey = toCamelCase(metricId)

        return (
            <React.Fragment>
                <div className={headerClassNames} ref={this.header}>
                    <p>&nbsp;</p>
                    <p>Rank</p>
                    <p>Name</p>
                    <h2 className={titleClassNames}>{title}</h2>
                    <p>Sharpe Ratio</p>
                </div>
                {this.hasRanking ? (
                    <React.Fragment>
                        <PaginatedAccordion
                            currentPage={currentPage}
                            pageCount={Math.max(1, pageCount)}
                            paginationClassName={paginationClassNames}
                            ref={this.accordion}
                            onPageChange={this.onPageChange}
                            onItemOpen={this.onRowExpanded}
                        >
                            {list.map(({portfolioId, ...rest}) => {
                                this.rows[portfolioId] = React.createRef()

                                return (
                                    <Accordion.Item
                                        headerTemplate={HeaderTemplate}
                                        isShowingPortfolioName={true}
                                        key={portfolioId}
                                        metricKey={metricKey}
                                        onClick={onAvatarClick}
                                        portfolioId={portfolioId}
                                        period={period}
                                        ref={this.rows[portfolioId]}
                                        {...rest}
                                    >
                                        <BodyTemplate
                                            period={period}
                                            portfolioId={portfolioId}
                                        />
                                    </Accordion.Item>
                                )
                            })}
                        </PaginatedAccordion>

                        <div className={linksClassNames}>
                            <button
                                className={linkClassNames}
                                onClick={this.handleJumpToTop}
                                style={{
                                    backgroundColor: 'transparent',
                                    border: 0,
                                }}
                            >
                                Jump to the top
                            </button>
                            <a
                                className={linkClassNames}
                                href={content.learnMoreUrl}
                                target="_blank"
                                rel="noopener noreferrer"
                            >
                                {content.learnMoreText}
                            </a>
                        </div>
                    </React.Fragment>
                ) : (
                    this.renderStatusBanner({hasErrors, isLoading})
                )}
            </React.Fragment>
        )
    }
}

LeaderboardTable.propTypes = {
    courseId: PropTypes.string,
    currentPage: PropTypes.number,
    getPortfolioSharpeTimeseries: PropTypes.func,
    getPublicPortfolio: PropTypes.func,
    getRank: PropTypes.func,
    getTimeseries: PropTypes.func,
    hasErrors: PropTypes.bool,
    isLoading: PropTypes.bool,
    list: PropTypes.array,
    metricId: PropTypes.oneOf(Object.values(metricIds)),
    metrics: PropTypes.object,
    openIndex: PropTypes.number,
    pageCount: PropTypes.number,
    period: PropTypes.oneOf(Object.values(rankingPeriods)),
    portfolios: PropTypes.array,
    setOpenIndex: PropTypes.func,
    setPage: PropTypes.func,
    showModal: PropTypes.func,
    timeseries: PropTypes.object,
    title: PropTypes.string,
    onAvatarClick: PropTypes.func,
}

LeaderboardTable.defaultProps = {
    list: [],
}

export default LeaderboardTable
