import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';

import {Icon} from '../../Icon';
import {playMessage} from '../../functions';
import lang from '../../../../lang/common/index-en_US';

export const ASC = 'ASC';
export const DESC = 'DESC';
export const KEY_ENTER = 13;
export const KEY_SPACE = 32;

export type CommonListSorterProps = {
    tagName: string;
    className: string;
    children?: React.ReactNode;
    append?: React.ReactNode;
    prepend?: React.ReactNode;
    property?: string;
    displayName?: string;
    ascendingText?: string;
    descendingText?: string;
    sorterTitleText?: string;
    testAutomationId: string;
    onChangeSorting?: any;
    direction?: any;
} & Partial<CommonListSorterDefaultProps>;

export type CommonListSorterDefaultProps = {
    tagName: 'th';
    className: '';
    append: null;
    prepend: null;
    property: string;
    displayName: string;
    ascendingText: string;
    descendingText: string;
    sorterTitleText: string;
    testAutomationId: null;
};

export class CommonListSorter<P extends CommonListSorterProps> extends React.Component<P> {
    static propTypes = {
        tagName: PropTypes.string,
        className: PropTypes.string,
        onChangeSorting: PropTypes.func.isRequired,
        direction: PropTypes.oneOf([null, ASC, DESC]).isRequired,
        children: PropTypes.node,
        append: PropTypes.node,
        prepend: PropTypes.node,
        property: PropTypes.string,
        displayName: PropTypes.string,
        ascendingText: PropTypes.string,
        descendingText: PropTypes.string,
        sorterTitleText: PropTypes.string,
        testAutomationId: PropTypes.string
    };

    static defaultProps = {
        tagName: 'th',
        className: '',
        children: null,
        append: null,
        prepend: null,
        property: '',
        displayName: '',
        get ascendingText() {
            return lang.SORT_BY_ASCENDING;
        },
        get descendingText() {
            return lang.SORT_BY_DESCENDING;
        },
        get sorterTitleText() {
            return lang.CLICK_TO_SORT;
        },
        testAutomationId: null
    };

    handleClick = () => {
        const {
            ascendingText = '',
            descendingText = '',
            displayName,
            property,
            children,
            onChangeSorting,
            direction
        } = this.props;
        const shouldReverse = direction === ASC;

        onChangeSorting(property, shouldReverse ? DESC : ASC);

        playMessage(
            shouldReverse
                ? descendingText.replace('{name}', displayName || children || (property as any))
                : ascendingText.replace('{name}', displayName || children || (property as any))
        );
    };

    sorterClassName() {
        const {direction} = this.props;

        return classnames('sortable', {
            'order-asc': direction === ASC,
            'order-desc': direction === DESC
        });
    }

    handleKeyDown = e => {
        if (e.keyCode === KEY_ENTER || e.keyCode === KEY_SPACE) {
            this.handleClick();
            e.preventDefault();
        }
    };

    getAccessibilityHeaderProps() {
        return {
            role: 'button',
            onKeyDown: this.handleKeyDown,
            tabIndex: 0,
            title: this.props.sorterTitleText
        };
    }

    getAriaSortName() {
        const {direction} = this.props;

        let sortName = 'none';
        if (direction === ASC) {
            sortName = 'ascending';
        }
        if (direction === DESC) {
            sortName = 'descending';
        }
        return sortName;
    }

    renderSorterIcon() {
        const {direction} = this.props;
        let iconName;

        if (direction === ASC) {
            iconName = 'chevron-down-small';
        }

        if (direction === DESC) {
            iconName = 'chevron-up-small';
        }

        let icon;
        if (iconName) {
            icon = <Icon aria-hidden="true" name={iconName} className="sorter-icon" />;
        } else {
            icon = (
                <Icon
                    aria-hidden="true"
                    name="chevron-down-small"
                    className="sorter-icon list-hover-arrow"
                />
            );
        }

        return <span className="column-header-right">{icon}</span>;
    }

    renderPrepend(prepend) {
        if (!prepend) {
            return null;
        }
        return <span>{prepend}</span>;
    }

    renderAppend(append) {
        if (!append) {
            return null;
        }
        return <span className="column-header-append">{append}</span>;
    }

    renderCellContent() {
        let {prepend, children, append} = this.props;
        return (
            <div className="column-header-content">
                {this.renderPrepend(prepend)}
                <div
                    className="column-header-label text-overflow"
                    {...this.getAccessibilityHeaderProps()}>
                    {children}
                </div>
                {this.renderAppend(append)}
                {this.renderSorterIcon()}
            </div>
        );
    }

    render() {
        let {
            tagName,
            onChangeSorting,
            direction,
            children,
            append,
            prepend,
            property,
            displayName,
            ascendingText,
            descendingText,
            sorterTitleText,
            testAutomationId,
            className,
            ...props
        } = this.props;

        const Tag: any = tagName;

        return (
            <Tag
                onClick={this.handleClick}
                role="columnheader"
                aria-sort={this.getAriaSortName()}
                data-test-automation-id={testAutomationId}
                className={classnames(className, this.sorterClassName())}
                {...props}>
                {this.renderCellContent()}
            </Tag>
        );
    }
}
