/**
 * The new input element
 *
 * @author Platon Fedorov
 * @date 2021-01-13
 */
import * as React from 'react';

import * as styles from './wrapper.m.scss';
import {joinClassNames, safeInvoke, SIZE} from '../../index';
import {renderIcon} from '../../utils/renderIcon';
import {getSizeThemeKey} from '../../utils/getSizeThemeKey';
import {SizeClassNames, Props} from './Wrapper.types';

export type WrapperProps = Props;

export class Wrapper extends React.Component<WrapperProps> {
    wrapperRef = React.createRef<HTMLDivElement>();

    constructor (props: WrapperProps) {
        super(props);

        this.onClickOutside = this.onClickOutside.bind(this);
    }

    override componentDidMount () {
        document.addEventListener('mousedown', this.onClickOutside);

        if (this.wrapperRef.current !== null && this.props.onWrapperFocus !== undefined) {
            this.wrapperRef.current.addEventListener('focus', this.props.onWrapperFocus);
        }
    }

    override componentWillUnmount () {
        document.removeEventListener('mousedown', this.onClickOutside);

        if (this.wrapperRef.current !== null && this.props.onWrapperFocus !== undefined) {
            this.wrapperRef.current.removeEventListener('focus', this.props.onWrapperFocus);
        }
    }

    createRef () {
        if (this.props.forwardRef) {
            this.wrapperRef = this.props.forwardRef;
        }

        return this.wrapperRef;
    }

    onClickOutside (e: MouseEvent) {
        if (this.wrapperRef.current && this.props.isFocused &&
            e.target instanceof Node && !this.wrapperRef.current.contains(e.target)
        ) {
            safeInvoke(this.props.onClickOutside, e);
        }
    }

    renderChild () {
        const {children} = this.props;

        return (
            <div
                tabIndex={-1}
                className={styles.child}
            >
                {children}
            </div>
        );
    }

    renderPrefix () {
        const {prefix, size, onPrefixClick} = this.props;

        const classPrefix = joinClassNames(
            styles.icon,
            styles.prefixIcon,
            [styles.iconIsClickable, Boolean(onPrefixClick)]
        );

        return prefix ? (
            renderIcon(this.props.prefix, {size}, {
                className: classPrefix,
                tabIndex: -1,
                onClick: onPrefixClick
            })) : null;
    }

    renderSuffix () {
        const {suffix, size, onSuffixClick} = this.props;

        const classSuffix = joinClassNames(
            styles.icon,
            styles.suffixIcon,
            [styles.iconIsClickable, Boolean(onSuffixClick)]
        );

        return suffix ? (
            renderIcon(this.props.suffix, {size}, {
                className: classSuffix,
                tabIndex: -1,
                onClick: onSuffixClick
            })) : null;
    }

    renderError () {
        const hasError = this.props.hasError,
            errorMessage = this.props.errorMessage;

        if (hasError && errorMessage) {
            return (
                <div className={styles.errorMessageContainer}>
                    {errorMessage}
                </div>
            );
        } else {
            return null;
        }
    }

    override render () {
        const {
            hasError,
            isFocused,
            transparent,
            isDisabled,
            isReadOnly,
            forwardRef,
            size = SIZE.MIDDLE,
            prefixRef,
            suffixRef,
            errorMessage,
            prefix,
            suffix,
            onPrefixClick,
            onSuffixClick,
            onBlur,
            onClickOutside,
            onWrapperFocus,
            ...props
        } = this.props;

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

        const classContainer = joinClassNames(
            styles.wrapperContainer,
            styles[sizeThemeKey],
            [styles.transparent, transparent === true],
            [styles.error, hasError === true],
            [styles.focused, isFocused === true],
            [styles.readonly, isReadOnly === true],
            [styles.disabled, isDisabled === true]
        );

        return (
            <>
                <div
                    {...props}
                    className={classContainer}
                    ref={this.createRef()}
                >
                    {this.renderPrefix()}
                    {this.renderChild()}
                    {this.renderSuffix()}
                </div>
                {this.renderError()}
            </>
        );
    }
}
