import _ from 'lodash';
import ClassNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import ReactDOM from 'react-dom';
import {
    columnPropTypesShape,
    columnPropsPropTypesShape,
} from './detailsWindowPropTypes';
import {
    UI_CLASS_NAME,
} from '../../global/constants';
import InfoBar from '../infoBar';
import DetailsWindowColumnContainer from './detailsWindowColumnContainer';
import domUtils from '../../utils/domUtils';

const propTypes = {
    bleed: PropTypes.bool,
    className: PropTypes.string,
    color: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]),
    columnProps: columnPropsPropTypesShape,
    columns: PropTypes.arrayOf(columnPropTypesShape).isRequired,
    data: PropTypes.shape({}).isRequired,
    /**
     * Used for DOM testing. https://testing-library.com/docs/queries/bytestid/
     */
    dataTestId: PropTypes.string,
    expandableColumns: PropTypes.arrayOf(columnPropTypesShape),
    forwardedRef: PropTypes.oneOfType([
        PropTypes.func,
        PropTypes.shape({
            current: PropTypes.instanceOf(Element),
        }),
    ]),
    moduleType: PropTypes.string,
    style: PropTypes.shape({}),
};

const defaultProps = {
    bleed: true,
    className: undefined,
    color: undefined,
    columnProps: undefined,
    dataTestId: `${UI_CLASS_NAME}-details_window`,
    expandableColumns: undefined,
    forwardedRef: undefined,
    moduleType: undefined,
    style: {},
};

class DetailsWindow extends React.PureComponent {
    constructor() {
        super();

        this.state = {
            isExpanded: false,
        };

        this.expandableContainerHeight = null;
        this.onExpandButtonToggle = this.onExpandButtonToggle.bind(this);
        this.onExpandTransitionComplete = this.onExpandTransitionComplete.bind(this);
        this.previousExpandableContainerHeight = null;
        this.setColumnContainerHeight = this.setColumnContainerHeight.bind(this);
    }

    componentDidMount() {
        this.toggleExpandableContainer();
    }

    componentDidUpdate(prevProps) {
        const { expandableColumns } = this.props;
        const { expandableColumns: prevExpandableColumns } = prevProps;

        if (_.isEmpty(prevExpandableColumns) && !_.isEmpty(expandableColumns)) {
            this.toggleExpandableContainer();
        }
    }

    onExpandButtonToggle() {
        this.setState((prevState) => ({
            isExpanded: !prevState.isExpanded,
        }), () => {
            this.toggleExpandableContainer();
        });
    }

    onExpandTransitionComplete() {
        const { moduleType } = this.props;
        const bemClassName = `${moduleType}--details_window`;
        const exandableContainer = ReactDOM.findDOMNode(this.exandableContainerRef); // eslint-disable-line react/no-find-dom-node, max-len

        exandableContainer.classList.remove(
            `${bemClassName}_exapndable_columns_container-contracted-active`,
            `${bemClassName}_exapndable_columns_container-expanded-active`,
        );
        exandableContainer.removeEventListener(
            domUtils.cssTransitionType(exandableContainer),
            this.onExpandTransitionComplete,
        );
    }

    setColumnContainerHeight(height) {
        if (_.isNil(this.expandableContainerHeight) || this.expandableContainerHeight > height) {
            this.expandableContainerHeight = height;
        }
    }

    toggleExpandableContainer() {
        const { expandableColumns, moduleType } = this.props;
        const bemClassName = `${moduleType}--details_window`;
        const { isExpanded } = this.state;
        const hasExpandableColumns = !_.isEmpty(expandableColumns);

        if (hasExpandableColumns && this.exandableContainerRef) {
            const exandableContainer = ReactDOM.findDOMNode(this.exandableContainerRef); // eslint-disable-line react/no-find-dom-node, max-len

            exandableContainer.style.height = `${isExpanded ? this.expandableContainerHeight : 0}px`;
            exandableContainer.classList.add(
                `${bemClassName}_exapndable_columns_container-${isExpanded ? 'expanded' : 'contracted'}-active`,
            );
            exandableContainer.addEventListener(
                domUtils.cssTransitionType(exandableContainer),
                this.onExpandTransitionComplete,
            );
        }
    }

    render() {
        const {
            bleed,
            className,
            color,
            columnProps,
            columns,
            data,
            dataTestId,
            expandableColumns,
            forwardedRef,
            style,
            moduleType,
        } = this.props;

        const { isExpanded } = this.state;
        const hasExpandableColumns = !_.isEmpty(expandableColumns);
        const bemClassName = `${moduleType}--details_window`;

        const containerClasses = ClassNames('ui', bemClassName, className, {
            [`${bemClassName}-bleed`]: bleed,
        });

        let detailsColumnKeyNum = 1;
        let detailsColumnKeyNumExpanded = 1;
        let horizontalSpacing;

        if (columnProps) {
            horizontalSpacing = columnProps.horizontalSpacing;
        }

        let expandableJSX;

        if (hasExpandableColumns) {
            const shouldShowExpanded = isExpanded;
            const expandableColumnsContainerName = `${bemClassName}_exapndable_columns_container`;
            const expandableContainerClasses = ClassNames(
                expandableColumnsContainerName,
                {
                    [`${expandableColumnsContainerName}-expanded`]: shouldShowExpanded,
                    [`${expandableColumnsContainerName}-contracted`]: !shouldShowExpanded,
                },
            );

            expandableJSX = (
                <div
                    className={expandableContainerClasses}
                    ref={(ref) => { this.exandableContainerRef = ref; }}
                >
                    {_.map(expandableColumns, (column) => {
                        detailsColumnKeyNumExpanded += 1;

                        return (
                            <DetailsWindowColumnContainer
                                column={column}
                                columnProps={columnProps}
                                data={data}
                                key={`${moduleType}DetailsColumn-${detailsColumnKeyNumExpanded}`}
                                moduleType={moduleType}
                                setColumnContainerHeight={this.setColumnContainerHeight}
                            />
                        );
                    })}
                </div>
            );
        }

        return (
            <div
                className={containerClasses}
                data-testid={dataTestId}
                ref={forwardedRef}
                style={style}
            >
                <InfoBar color={color}>
                    <div
                        className={`${bemClassName}_columns_container`}
                        style={{
                            marginLeft: horizontalSpacing ? `-${horizontalSpacing}px` : null,
                            marginRight: horizontalSpacing ? `-${horizontalSpacing}px` : null,
                        }}
                    >
                        {_.map(columns, (column) => {
                            detailsColumnKeyNum += 1;

                            return (
                                <DetailsWindowColumnContainer
                                    column={column}
                                    columnProps={columnProps}
                                    data={data}
                                    isExpanded={isExpanded}
                                    key={`${moduleType}DetailsColumn-${detailsColumnKeyNum}`}
                                    moduleType={moduleType}
                                    onExpandButtonToggle={this.onExpandButtonToggle}
                                />
                            );
                        })}
                    </div>

                    {expandableJSX}
                </InfoBar>
            </div>
        );
    }
}

DetailsWindow.propTypes = propTypes;
DetailsWindow.defaultProps = defaultProps;

export default DetailsWindow;
