/**
 * Drawer component
 *
 * @author Brauer Ilya
 * @date 2020-12-04
 */
import * as React from 'react';
import {joinClassNames, Overlay, SIZE} from '../../index';

import * as styles from './drawer.m.scss';
import {getSizeThemeKey} from '../../utils/getSizeThemeKey';
import {SizeClassNames} from '../../type/SizeTypes';

type DrawerPosition = 'right' | 'bottom';
type DrawerTheme = 'light' | 'dark';

interface IProps {
    isOpen: boolean;
    onClose: (e: Event | React.SyntheticEvent<HTMLDivElement>) => void;
    parentContainer?: HTMLElement;
    title?: string;
    leftExtraItems?: React.ReactNode;
    rightExtraItems?: React.ReactNode;
}

interface IDefProps {
    hasBackdrop: boolean;
    shouldCloseOnClickOutside: boolean;
    shouldCloseOnEsc: boolean;
    position: DrawerPosition;
    size: SIZE;
    theme: DrawerTheme;
}

interface IState {
    isOpen: boolean;
}

export class Drawer extends React.PureComponent<IProps & Partial<IDefProps>, IState> {

    static defaultProps: IDefProps = {
        hasBackdrop: true,
        shouldCloseOnClickOutside: true,
        shouldCloseOnEsc: true,
        size: SIZE.MIDDLE,
        position: 'right',
        theme: 'light'
    };

    drawerRef = React.createRef<HTMLDivElement>();

    override state: IState = {
        isOpen: this.props.isOpen
    };

    override componentDidMount (): void {
        this.updateIsOpenDrawer();
    }

    override componentDidUpdate (prevProps: Readonly<IProps & Partial<IDefProps>>, prevState: Readonly<IState>, snapshot?: any): void {
        if (prevProps.isOpen !== this.props.isOpen) {
            this.updateIsOpenDrawer();
        }
    }

    updateIsOpenDrawer = () => {
        if (this.props.isOpen !== this.state.isOpen && !this.state.isOpen) {
            this.setState({
                isOpen: true
            }, () => {
                if (this.props.parentContainer) {
                    this.calcSize();
                }
            });
        }
    };

    calcSize = () => {
        if (this.props.parentContainer) {
            const boundaryRect = this.props.parentContainer.getBoundingClientRect();

            if (this.drawerRef.current) {
                if (this.props.position === 'bottom') {
                    this.drawerRef.current.style.left = boundaryRect.left + 10 + 'px';
                    this.drawerRef.current.style.right = '0px';
                    this.drawerRef.current.style.width = boundaryRect.width - 20 + 'px';
                } else if (this.props.position === 'right') {
                    this.drawerRef.current.style.top = boundaryRect.top + 10 + 'px';
                    this.drawerRef.current.style.bottom = '0px';
                    this.drawerRef.current.style.height = boundaryRect.height - 20 + 'px';
                }
            }
        }
    };

    updateIsOpenDrawerAfterAnimation = () => {
        if (this.props.isOpen !== this.state.isOpen &&
            this.state.isOpen
        ) {
            this.setState({
                isOpen: false
            });
        }
    };

    get hasHeader () {
        return this.props.title || this.props.rightExtraItems || this.props.leftExtraItems;
    }

    override render () {
        const {
            onClose,
            hasBackdrop,
            shouldCloseOnClickOutside,
            shouldCloseOnEsc,
            size,
            title,
            leftExtraItems,
            rightExtraItems
        } = this.props;

        let sizeClassName;

        if (size) {
            const sizeThemeKey = getSizeThemeKey<SizeClassNames>('', size);

            sizeClassName = styles[sizeThemeKey];
        }

        const classNameContainer = joinClassNames(
            styles.container,
            sizeClassName,
            [styles.positionRight, this.props.position === 'right'],
            [styles.positionBottom, this.props.position === 'bottom'],
            [styles.noBackdrop, this.props.hasBackdrop !== true],
            [styles.animationShow, this.props.isOpen],
            [styles.animationHide, !this.props.isOpen],
            [styles.darkTheme, this.props.theme === 'dark'],
            [styles.lightTheme, this.props.theme === 'light'],
            [styles.hasParent, this.props.parentContainer !== undefined]
        );

        const classNameContent = joinClassNames(
            styles.content,
            [styles.withTitle, title !== undefined]
        );

        const leftExtraStyles = joinClassNames(
            styles.extraItemsContainer,
            styles.leftExtraItemsContainer
        );

        return (
            <Overlay
                isOpen={this.state.isOpen}
                hasBackdrop={hasBackdrop}
                shouldCloseOnClickOutside={shouldCloseOnClickOutside}
                shouldCloseOnEsc={shouldCloseOnEsc}
                onClose={onClose}
            >
                <div
                    className={classNameContainer}
                    onAnimationEnd={this.updateIsOpenDrawerAfterAnimation}
                    data-component-id={'Drawer'}
                    ref={this.drawerRef}
                >
                    {this.hasHeader && (
                        <div className={styles.header}>
                            <div className={styles.leftItems}>
                                {leftExtraItems && (<div className={leftExtraStyles}>{leftExtraItems}</div>)}
                                <div className={styles.cardTitle}>{title}</div>
                            </div>
                            <div className={styles.extraItemsContainer}>{rightExtraItems}</div>
                        </div>
                    )}
                    <div className={classNameContent}>
                        {this.props.children}
                    </div>
                </div>
            </Overlay>
        );
    }
}
