/**
 * Date range picker component
 *
 * @author Fedorov Platon
 * @date 2021-06-25
 */

import * as React from 'react';
import {Input} from '../input/Input';
import {POPOVER_BOUNDARIES, TRIGGER} from '../../constants';
import {Calendar} from '../calendar/Calendar';
import {CalendarProps} from '../calendar/Calendar.types';
import {DropDown} from '../dropdown/DropDown';
import {safeInvoke} from '../../utils/safeInvoke';
import moment from 'moment';
import * as styles from './dateRangePicker.m.scss';
import {AdditionalTemplates, TemplateDate} from '../date_picker/AdditionalTemplates';
import {Wrapper} from '../wrapper/Wrapper';
import {joinClassNames} from '../../utils/joinClassNames';
import {parseNoSeparatedDate} from '../../utils/parseNoSeparatedDate';
import ReactInputMask from 'react-input-mask';
import {formatChars} from '../input/InputMask';
import {Icon} from '../icon/Icon';

const defaultProps = {
    mode: 'month',
    pickerType: 'dateRange',
    isInline: false
};

export type DateRangePickerProps = Omit<CalendarProps,
    'value' | 'fullscreen' | 'onSelect' | 'onChange' | 'mode' | 'defaultValue'> & {
    autoFocus?: boolean;
    allowClear?: boolean;
    errorMessage?: React.ReactNode;
    viewFormat: string;
    valueFormat: string;
    isReadOnly?: boolean;
    isDisabled?: boolean;
    placeholder?: [string, string];
    mode?: 'month' | 'year';
    isDefaultOpen?: boolean;
    isOpen?: boolean;
    isUtc?: boolean;
    onVisibleChange?: (isOpen: boolean) => void;
    onClose?: () => void;
    onBlur?: () => void;
    value?: [string, string];
    defaultValue?: [string, string];
    onChange?: (dateArray: [string, string]) => void;
    pickerType?: 'dateRange' | 'dateTimeRange';
    isInline?: boolean;
    additionalDateTemplates?: DateRangeTemplate[];
    errorTimeMessage: string;
}

export type DateRangeTemplate = {
    date: [string, string] | [moment.Moment, moment.Moment];
    name: string;
};

interface IState {
    isOpen: boolean;
    textFrom: string;
    textTo: string;
    dateFrom: moment.Moment | undefined;
    dateTo: moment.Moment | undefined;
    timeFrom: string;
    timeTo: string;
    isFocused: boolean;
    isSetFrom: boolean;
    isTargetHovered: boolean;
    textFromPossible: string | undefined;
    textToPossible: string | undefined;
}

export class DateRangePicker extends React.Component<DateRangePickerProps, IState> {
    static defaultProps = defaultProps;

    constructor (props: DateRangePickerProps) {
        super(props);
        let textFrom = '';
        let textTo = '';
        let dateFrom: moment.Moment | undefined;
        let dateTo: moment.Moment | undefined;
        let parsedDateFrom, parsedDateTo;

        if (props.value && !props.defaultValue) {
            parsedDateFrom = this.getMoment(props.value[0], props.valueFormat);
            parsedDateTo = this.getMoment(props.value[1], props.valueFormat);
        }

        if (props.defaultValue) {
            parsedDateFrom = this.getMoment(props.defaultValue[0], props.valueFormat);
            parsedDateTo = this.getMoment(props.defaultValue[1], props.valueFormat);
        }

        if (parsedDateFrom && parsedDateFrom.isValid()) {
            textFrom = parsedDateFrom.format(this.viewFormat);
            dateFrom = parsedDateFrom;
        }

        if (parsedDateTo && parsedDateTo.isValid()) {
            textTo = parsedDateTo.format(this.viewFormat);
            dateTo = parsedDateTo;
        }

        this.state = {
            isOpen: props.isOpen || props.isDefaultOpen || false,
            textFrom: textFrom,
            textTo: textTo,
            dateFrom: dateFrom,
            timeFrom: dateFrom ? dateFrom.format(this.timeFormat) : '',
            dateTo: dateTo,
            timeTo: dateFrom ? dateFrom.format(this.timeFormat) : '',
            isSetFrom: true,
            isFocused: Boolean(props.isInline),
            isTargetHovered: false,
            textFromPossible: undefined,
            textToPossible: undefined
        };
    }

    wrapperContainer = React.createRef<HTMLDivElement>();
    inputFrom = React.createRef<HTMLInputElement>();
    inputTo = React.createRef<HTMLInputElement>();
    calendar = React.createRef<HTMLDivElement>();
    isFromFilled = false;
    isToFilled = false;
    isPanelChanged = false;
    isMount = false;

    override componentDidMount () {
        this.isMount = true;
    }

    get viewFormat (): string {
        return this.props.viewFormat;
    }

    get valueFormat (): string {
        return this.props.valueFormat;
    }

    get timeFormat (): string {
        return 'HH:mm:ss';
    }

    get viewMask (): string {
        return this.viewFormat.replace(/\w/g, '9');
    }

    get viewEmptyMask (): string {
        return this.viewFormat.replace(/\w/g, '_');
    }

    private getMoment (value?: string, valueFormat?: string): moment.Moment {
        return this.isUTC ? moment.utc(value, valueFormat) : moment(value, valueFormat);
    }

    private get isUTC () {
        return this.props.isUtc || false;
    }

    isDateDisabled = (isFrom: boolean) => (date: moment.Moment) => {
        if (this.props.disabledDate && this.props.disabledDate(date)) {
            return true;
        }

        if (isFrom && this.state.dateTo) {
            return date.diff(this.state.dateTo) > 0;
        } else if (!isFrom && this.state.dateFrom) {
            return date.diff(this.state.dateFrom) < 0;
        }

        return false;
    }

    isValidRange = (date: moment.Moment) => {
        if (!this.props.validRange) {
            return true;
        }

        const validRange = this.props.validRange;

        return date.diff(validRange[0]) >= 0 && date.diff(validRange[1]) <= 0;
    }

    onInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
        if (this.props.isInline) {
            if (e.key === 'Enter') {
                if (e.currentTarget === this.inputFrom.current) {
                    this.inputTo.current?.focus();
                } else {
                    this.inputFrom.current?.focus();
                }
            }
        } else {
            if (e.key === 'Enter') {
                if (e.currentTarget === this.inputFrom.current) {
                    if (this.state.isOpen) {
                        this.inputFrom.current?.blur();
                        this.switchInput(true)();
                    } else {
                        this.onVisibleChange(true);
                    }
                } else {
                    this.inputTo.current?.blur();
                    this.switchInput(false)();
                }
            }

            if (e.key === 'Tab' && e.currentTarget === this.inputTo.current) {
                this.inputTo.current?.blur();
                this.onVisibleChange(false);
                this.onDatePickerBlur();
            }
        }
    }

    onInputFocus = () => {
        const isSetFrom = document.activeElement === this.inputFrom.current;

        if (this.props.isInline) {
            if (this.isMount) {
                this.setState({
                    isSetFrom: isSetFrom
                });
            }

            return;
        }

        if (!this.state.isOpen) {
            this.setState({
                isOpen: true,
                isFocused: true,
                isSetFrom: isSetFrom
            });

            safeInvoke(this.props.onVisibleChange, true);
        } else {
            this.setState({
                isSetFrom: isSetFrom
            });
        }
    }

    onInputBlur = (isFrom: boolean) => () => {
        const {dateFrom, dateTo} = this.state;
        const date = isFrom ? dateFrom : dateTo;
        const textDate = date ? date.format(this.viewFormat) : '';
        const timeDate = date ? date.format(this.timeFormat) : '';
        const clearAnother = date ? this.isDateDisabled(isFrom)(date) : false;

        if (isFrom) {
            this.isFromFilled = true;

            this.setState((prevState) => {
                return {
                    textFrom: textDate,
                    timeFrom: timeDate,
                    dateTo: clearAnother ? undefined : prevState.dateTo,
                    textTo: clearAnother ? '' : prevState.textTo,
                    timeTo: clearAnother ? '' : prevState.timeTo
                };
            });

            this.onChange(dateFrom, clearAnother ? undefined : dateTo);
        } else {
            this.isToFilled = true;

            this.setState((prevState) => {
                return {
                    dateFrom: clearAnother ? undefined : prevState.dateFrom,
                    textFrom: clearAnother ? '' : prevState.textFrom,
                    timeFrom: clearAnother ? '' : prevState.timeFrom,
                    textTo: textDate,
                    timeTo: timeDate
                };
            });

            this.onChange(clearAnother ? undefined : dateFrom, dateTo);
        }
    }

    onInputChange = (isFrom: boolean) => (e: React.ChangeEvent<HTMLInputElement>) => {
        const text = e.currentTarget.value;
        const isTextEmpty = text === this.viewEmptyMask;

        if (isTextEmpty) {
            if (isFrom) {
                this.setState({textFrom: text, dateFrom: undefined});
            } else {
                this.setState({textTo: text, dateTo: undefined});
            }
        } else {
            const date = parseNoSeparatedDate(text, this.viewFormat, this.isUTC);

            if (date && date.isValid() && this.isValidRange(date)) {
                if (isFrom) {
                    this.setState({
                        textFrom: text,
                        dateFrom: date,
                        timeFrom: date.format(this.timeFormat),
                        isOpen: true
                    });
                } else {
                    this.setState({
                        textTo: text,
                        timeTo: date.format(this.timeFormat),
                        dateTo: date
                    });
                }
            } else {
                if (isFrom) {
                    this.setState({textFrom: text, isOpen: true});
                } else {
                    this.setState({textTo: text});
                }
            }
        }
    }

    onInputFromClick = () => {
        if (!this.props.isInline && this.state.isSetFrom && this.state.isOpen === false) {
            this.onVisibleChange(true);
        }
    }

    onWrapperMouseEnter = () => {
        this.setState({isTargetHovered: true});
    }

    onWrapperMouseLeave = () => {
        this.setState({isTargetHovered: false});
    }

    onWrapperClickOutside = () => {
        if (this.props.isInline === false && this.state.isOpen === false) {
            this.onDatePickerBlur();
        }
    }

    onDatePickerBlur = () => {
        this.isFromFilled = false;
        this.isToFilled = false;

        const dateFrom = this.state.dateFrom;
        const dateTo = this.state.dateTo;

        this.setState({
            isOpen: false,
            isSetFrom: true,
            isFocused: Boolean(this.props.isInline),
            dateFrom: dateFrom,
            dateTo: dateTo,
            textFrom: dateFrom ? dateFrom.format(this.viewFormat) : '',
            textTo: dateTo ? dateTo.format(this.viewFormat) : '',
            timeFrom: dateFrom ? dateFrom.format(this.timeFormat) : '',
            timeTo: dateTo ? dateTo.format(this.timeFormat) : ''
        });

        this.onChange(dateFrom, dateTo);

        if (!this.props.isInline) {
            safeInvoke(this.props.onBlur);
        }
    }

    onClear = () => {
        this.isFromFilled = false;
        this.isToFilled = false;

        this.setState({
            dateFrom: undefined,
            dateTo: undefined,
            textFrom: '',
            textTo: '',
            timeFrom: '',
            timeTo: ''
        });

        this.onChange(undefined, undefined);
        this.inputFrom.current?.focus();
    }

    onVisibleChange = (visible: boolean) => {
        const isOpen = this.state.isOpen;

        if (visible && !isOpen) {
            this.setState({isOpen: visible});
            safeInvoke(this.props.onVisibleChange, visible);
        } else if (!visible && isOpen) {
            this.setState({isOpen: visible});
            safeInvoke(this.props.onClose);
            safeInvoke(this.props.onVisibleChange, false);
        }
    }

    onDropDownClose = (e: React.SyntheticEvent<Element> | Event) => {
        const isEsc = e instanceof KeyboardEvent;

        if (isEsc ||
            (this.wrapperContainer.current &&
                e.target instanceof Node && !this.wrapperContainer.current.contains(e.target))
        ) {
            if (!this.state.isSetFrom) {
                this.onVisibleChange(false);
            }

            if (!isEsc) {
                this.onDatePickerBlur();
            } else {
                this.inputTo.current?.focus();
            }
        }
    }

    onChange = (dateFrom?: moment.Moment, dateTo?: moment.Moment) => {
        const dateFromValueFormatted = dateFrom ? dateFrom.format(this.valueFormat) : '';
        const dateToValueFormatted = dateTo ? dateTo.format(this.valueFormat) : '';
        const value = this.props.value;

        if (value === undefined || value[0] !== dateFromValueFormatted || value[1] !== dateToValueFormatted) {
            safeInvoke(this.props.onChange, [dateFromValueFormatted, dateToValueFormatted]);
        }
    }

    switchInput = (isFrom: boolean) => () => {
        if (this.isPanelChanged) {
            this.isPanelChanged = false;

            return;
        }

        if (isFrom) {
            this.isFromFilled = true;
        } else {
            this.isToFilled = true;
        }

        if (!this.props.isInline && this.isFromFilled && this.isToFilled) {
            this.inputFrom.current?.focus();
            this.isFromFilled = false;
            this.isToFilled = false;
            this.onVisibleChange(false);

            return;
        }

        if (isFrom) {
            this.inputTo.current?.focus();
        } else {
            this.inputFrom.current?.focus();
        }
    }

    onCalendarPanelChange = (date: moment.Moment, mode: 'year' | 'month') => {
        this.isPanelChanged = true;

        safeInvoke(this.props.onPanelChange, date, mode);
    }

    onCalendarSelect = (isFrom: boolean) => (date: moment.Moment) => {
        const timeInState = isFrom ? this.state.timeFrom : this.state.timeTo;
        const dateFrom = isFrom ? date : this.state.dateFrom;
        const dateTo = isFrom ? this.state.dateTo : date;

        if (timeInState === '') {
            date.hours(0);
            date.minutes(0);
            date.seconds(0);
        }

        if (!this.isDateDisabled(isFrom)(date)) {
            if (isFrom) {
                this.setState({
                    dateFrom: date,
                    textFrom: date.format(this.viewFormat),
                    timeFrom: date.format(this.timeFormat),
                    textFromPossible: undefined
                }, this.switchInput(isFrom));
            } else {
                this.setState({
                    dateTo: date,
                    textTo: date.format(this.viewFormat),
                    timeTo: date.format(this.timeFormat),
                    textToPossible: undefined
                }, this.switchInput(isFrom));
            }
        }

        this.onChange(dateFrom, dateTo);
    }

    onAdditionalTemplateClickCallback = () => {
        if (!this.props.isInline) {
            this.inputTo.current?.focus();
            this.onVisibleChange(false);
        }
    }

    onAdditionalTemplateClick = (date: TemplateDate) => {
        let templateFrom: string | moment.Moment | undefined;
        let templateTo: string | moment.Moment | undefined;

        if (!Array.isArray(date)) {
            templateFrom = date;
            templateTo = date;
        } else {
            templateFrom = date[0];
            templateTo = date[1];
        }

        const [dateFrom, dateTo] = typeof templateFrom === 'string' && typeof templateTo === 'string' ?
            [this.getMoment(templateFrom, this.valueFormat), this.getMoment(templateTo, this.valueFormat)] : [templateFrom, templateTo];

        if (typeof dateFrom === 'string' || typeof dateTo === 'string') {
            return;
        }

        this.setState({
            dateFrom: dateFrom,
            textFrom: dateFrom.format(this.viewFormat),
            timeFrom: dateFrom.format(this.timeFormat),
            dateTo: dateTo,
            textTo: dateTo.format(this.viewFormat),
            timeTo: dateTo.format(this.timeFormat)
        }, this.onAdditionalTemplateClickCallback);

        this.onChange(dateFrom, dateTo);
    }

    onTimeInputBlur = (isFrom: boolean) => () => {
        const time = isFrom ? this.state.timeFrom : this.state.timeTo;
        const isTimeValid = /^(([01][0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]$/.test(time);
        const {dateFrom, dateTo} = this.state;
        const isClearTime = time === '__:__:__' && ((isFrom && dateFrom) || (!isFrom && dateTo));

        let dateToSet = isFrom ? dateFrom?.clone() : dateTo?.clone();

        if (isClearTime && dateToSet) {
            dateToSet.hours(0);
            dateToSet.minutes(0);
            dateToSet.seconds(0);
        }

        if (isTimeValid) {
            const [h, m, s] = time.split(':').map((item) => parseInt(item));

            if (dateToSet === undefined) {
                dateToSet = this.getMoment(time, this.timeFormat);
            } else {
                if (dateToSet.hours() !== h || dateToSet.minutes() !== m || dateToSet.seconds() !== s) {
                    dateToSet.hours(h);
                    dateToSet.minutes(m);
                    dateToSet.seconds(s);
                }
            }
        }

        if (!isTimeValid && !isClearTime) {
            if (isFrom) {
                this.setState({
                    timeFrom: dateToSet ? dateToSet.format(this.timeFormat) : ''
                });
            } else {
                this.setState({
                    timeTo: dateToSet ? dateToSet.format(this.timeFormat) : ''
                });
            }
        } else if (dateToSet) {
            if (isFrom) {
                this.setState({
                    dateFrom: dateToSet,
                    textFrom: dateToSet.format(this.viewFormat)
                });

                this.onChange(dateToSet, dateTo);
            } else {
                this.setState({
                    dateTo: dateToSet,
                    textTo: dateToSet.format(this.viewFormat)
                });

                this.onChange(dateToSet, dateTo);
            }
        }
    }

    onTimeInputChange = (isFrom: boolean) => (e: React.ChangeEvent<HTMLInputElement>) => {
        if (isFrom) {
            this.setState({timeFrom: e.target.value});
        } else {
            this.setState({timeTo: e.target.value});
        }
    }

    onCellMouseEnter = (date: moment.Moment) => () => {
        const isFrom = this.state.isSetFrom;
        const currentDate = isFrom ? this.state.dateFrom : this.state.dateTo;

        date.hours(currentDate ? currentDate.hours() : 0);
        date.minutes(currentDate ? currentDate.minutes() : 0);
        date.seconds(currentDate ? currentDate.seconds() : 0);

        if (!this.isDateDisabled(isFrom)(date) && this.isValidRange(date)) {
            if (isFrom) {
                this.setState({textFromPossible: date.format(this.viewFormat)});
            } else {
                this.setState({textToPossible: date.format(this.viewFormat)});
            }
        }
    }

    onCellMouseLeave = () => {
        this.setState({textFromPossible: undefined, textToPossible: undefined});
    }

    renderDateFullCell = (date: moment.Moment) => {
        if (this.props.dateFullCellRender) {
            return this.props.dateFullCellRender(date);
        }

        const dateFrom = this.state.dateFrom?.clone().startOf('date');
        const dateTo = this.state.dateTo?.clone().startOf('date');
        const dateRender = date.clone().startOf('date');
        const isEdgeDate = (dateFrom && dateFrom.diff(dateRender) === 0) || (dateTo && dateTo.diff(dateRender) === 0);
        const isDateBetween = dateFrom && dateTo && (dateRender.diff(dateFrom) >= 0 && dateRender.diff(dateTo) <= 0);
        const isPossibleDate = this.state.textFromPossible && this.state.dateTo || this.state.dateFrom && this.state.textToPossible;

        let containerClassName = styles.dateFullCellContainer;
        let valueClassName;


        if (isEdgeDate) {
            valueClassName = joinClassNames(styles.dateFullCellValue, styles.edgeDate);
        } else if (isDateBetween) {
            valueClassName = joinClassNames(styles.dateFullCellValue, styles.betweenDate);
        } else  {
            valueClassName = styles.dateFullCellValue;
        }

        if (isPossibleDate) {
            if (this.state.textFromPossible && this.state.dateTo) {
                const possibleDateFrom = this.getMoment(this.state.textFromPossible, this.viewFormat).startOf('date');

                if (dateRender.diff(possibleDateFrom) >= 0 && dateRender.diff(dateTo) <= 0) {
                    valueClassName = joinClassNames(valueClassName, styles.possibleDate);
                }
            } else {
                const possibleDateTo = this.getMoment(this.state.textToPossible, this.viewFormat).startOf('date');

                if (dateRender.diff(dateFrom) >= 0 && dateRender.diff(possibleDateTo) <= 0) {
                    valueClassName = joinClassNames(valueClassName, styles.possibleDate);
                }
            }
        }

        if (this.props.mode === 'month') {
            return (
                <div
                    className={containerClassName}
                    onMouseEnter={this.onCellMouseEnter(date)}
                    onMouseLeave={this.onCellMouseLeave}
                >
                    <div className={valueClassName}>
                        {date.date()}
                    </div>
                </div>
            );
        }

        return null;
    }

    renderWrapper = (textFrom: string, textTo: string) => {
        const isInputReadonly = this.props.isDisabled || this.props.isReadOnly;
        const valueFrom = this.state.textFromPossible ? this.state.textFromPossible : textFrom;
        const valueTo = this.state.textToPossible ? this.state.textToPossible : textTo;
        const placeholder = this.props.placeholder;
        const allowClear = this.props.allowClear && this.state.isTargetHovered && !isInputReadonly;
        const onMouseEnter = this.props.allowClear ? this.onWrapperMouseEnter : undefined;
        const onMouseLeave = this.props.allowClear ? this.onWrapperMouseLeave : undefined;
        const isFromFocused = document.activeElement === this.inputFrom.current;
        const isToFocused = document.activeElement === this.inputTo.current;

        return (
            <div className={styles.wrapperContainer} ref={this.wrapperContainer}>
                <Wrapper
                    isFocused={isInputReadonly ? false : this.state.isFocused}
                    isDisabled={this.props.isDisabled}
                    isReadOnly={this.props.isReadOnly}
                    hasError={Boolean(this.props.errorMessage)}
                    errorMessage={this.props.errorMessage}
                    onMouseEnter={onMouseEnter}
                    onMouseLeave={onMouseLeave}
                    onClickOutside={this.onWrapperClickOutside}
                >
                    <div className={styles.wrapperContentContainer}>
                        <ReactInputMask
                            mask={this.viewMask}
                            value={valueFrom}
                            onChange={this.onInputChange(true)}
                            formatChars={formatChars}
                            onBlur={this.onInputBlur(true)}
                            onFocus={this.onInputFocus}
                            size={this.viewFormat.length}
                            readOnly={isInputReadonly}
                            disabled={isInputReadonly}
                        >
                            {(inputProps: React.HTMLAttributes<HTMLInputElement>) => {
                                return (
                                    <input
                                        {...inputProps}
                                        className={!isFromFocused && isToFocused ? styles.unfocusedValue : undefined}
                                        id={'inputFrom'}
                                        onKeyDown={this.onInputKeyDown}
                                        onClick={this.onInputFromClick}
                                        autoFocus={this.props.autoFocus}
                                        placeholder={placeholder ? placeholder[0] : undefined}
                                        readOnly={isInputReadonly}
                                        disabled={isInputReadonly}
                                        ref={this.inputFrom}
                                    />
                                );
                            }}
                        </ReactInputMask>
                        <label htmlFor="inputFrom">&nbsp;-&nbsp;</label>
                        <ReactInputMask
                            mask={this.viewMask}
                            value={valueTo}
                            onChange={this.onInputChange(false)}
                            formatChars={formatChars}
                            onBlur={this.onInputBlur(false)}
                            onFocus={this.onInputFocus}
                            size={this.viewFormat.length}
                            readOnly={isInputReadonly}
                            disabled={isInputReadonly}
                        >
                            {(inputProps: React.HTMLAttributes<HTMLInputElement>) => {
                                return (
                                    <input
                                        {...inputProps}
                                        className={!isToFocused && isFromFocused ? styles.unfocusedValue : undefined}
                                        onKeyDown={this.onInputKeyDown}
                                        placeholder={placeholder ? placeholder[1] : undefined}
                                        readOnly={isInputReadonly}
                                        disabled={isInputReadonly}
                                        ref={this.inputTo}
                                    />
                                );
                            }}
                        </ReactInputMask>
                        {
                            allowClear ? (
                                <Icon name={'cross'} onClick={this.onClear}/>
                            ) : (
                                <Icon name={'calendar-empty'}/>
                            )
                        }
                    </div>
                </Wrapper>
            </div>
        );
    }

    renderSecondCalendarHeader = () => {
        return null;
    }

    renderCalendar = (dateFrom: moment.Moment, dateTo: moment.Moment, isFrom: boolean, props: any) => {
        const date = isFrom ? dateFrom : dateTo;
        const renderDateFullCell = this.props.mode !== 'year' ? this.renderDateFullCell : undefined;
        const isDisabled = this.props.isDisabled || this.props.isReadOnly;


        let dateSecond;

        if (this.props.mode !== 'month') {
            dateSecond = date.clone().startOf('year').add(1, 'year');
        } else {
            dateSecond = date.clone().startOf('month').add(1, 'month');
        }

        return (
            <>
                <div className={styles.calendarsContainer}>
                    <Calendar
                        {...props}
                        fullscreen={false}
                        value={date}
                        onSelect={this.onCalendarSelect(isFrom)}
                        disabledDate={this.isDateDisabled(isFrom)}
                        dateFullCellRender={renderDateFullCell}
                        onPanelChange={this.onCalendarPanelChange}
                        isDisabled={isDisabled}
                        showSearch={true}
                    />
                    <div className={styles.secondCalendar}>
                        <Calendar
                            fullscreen={false}
                            value={dateSecond}
                            onSelect={this.onCalendarSelect(isFrom)}
                            disabledDate={this.isDateDisabled(isFrom)}
                            dateFullCellRender={renderDateFullCell}
                            headerRender={this.renderSecondCalendarHeader}
                            isDisabled={isDisabled}
                            showSearch={true}
                            {...props}
                        />
                    </div>
                </div>
                {this.props.pickerType === 'dateTimeRange' && (
                    <div className={styles.inputTimeContainer}>
                        {
                            isFrom ? (
                                <Input.Time
                                    key={'timeFrom'}
                                    value={this.state.timeFrom}
                                    onChange={this.onTimeInputChange(true)}
                                    onBlur={this.onTimeInputBlur(true)}
                                    errorMessage={this.props.errorTimeMessage}
                                    allowClear={false}
                                />
                            ) : (
                                <Input.Time
                                    key={'timeTo'}
                                    value={this.state.timeTo}
                                    onChange={this.onTimeInputChange(false)}
                                    onBlur={this.onTimeInputBlur(false)}
                                    errorMessage={this.props.errorTimeMessage}
                                    allowClear={false}
                                />
                            )
                        }
                    </div>
                )}
                {
                    this.props.additionalDateTemplates && (
                        <AdditionalTemplates
                            dates={this.props.additionalDateTemplates}
                            onClick={this.onAdditionalTemplateClick}
                            isDisabled={isDisabled}
                        />
                    )
                }
            </>
        );
    }

    override render () {
        const {
            value,
            autoFocus,
            allowClear,
            errorMessage,
            isReadOnly,
            isDisabled,
            placeholder,
            viewFormat,
            valueFormat,
            onChange,
            disabledDate,
            defaultValue,
            onClose,
            ...props
        } = this.props;

        const isOpen = this.props.isOpen === undefined ? this.state.isOpen : this.props.isOpen;
        const isFrom = this.state.isSetFrom;
        const isFocused = this.state.isFocused;

        let dateFrom: moment.Moment | undefined;
        let dateTo: moment.Moment | undefined;
        let textFrom: string;
        let textTo: string;

        if (value === undefined || isFocused) {
            if (value && this.props.isInline) {
                if (document.activeElement === this.inputFrom.current) {
                    dateFrom = this.state.dateFrom;
                    textFrom = this.state.textFrom;
                } else {
                    dateFrom = value[0] === '' ? undefined : this.getMoment(value[0], this.valueFormat);
                    textFrom = dateFrom ? dateFrom.format(this.viewFormat) : '';
                }

                if (document.activeElement === this.inputTo.current) {
                    dateTo = this.state.dateTo;
                    textTo = this.state.textTo;
                } else {
                    dateTo = value[1] === '' ? undefined : this.getMoment(value[1], this.valueFormat);
                    textTo = dateTo ? dateTo.format(this.viewFormat) : '';
                }
            } else {
                dateFrom = this.state.dateFrom;
                dateTo = this.state.dateTo;
                textFrom = this.state.textFrom;
                textTo = this.state.textTo;
            }
        } else {
            dateFrom = value[0] === '' ? undefined : this.getMoment(value[0], this.valueFormat);
            dateTo = value[1] === '' ? undefined : this.getMoment(value[1], this.valueFormat);
            textFrom = dateFrom ? dateFrom.format(this.viewFormat) : '';
            textTo = dateTo ? dateTo.format(this.viewFormat) : '';
        }

        if (!dateFrom && dateTo) {
            dateFrom = dateTo;
        } else if (!dateTo && dateFrom) {
            dateTo = dateFrom;
        }

        if (!dateFrom) {
            dateFrom = this.getMoment();
        }

        if (!dateTo) {
            dateTo = this.getMoment();
        }

        if (this.props.isInline) {
            return (
                <div className={styles.inlineContainer}>
                    {this.renderWrapper(textFrom, textTo)}
                    {this.renderCalendar(dateFrom, dateTo, isFrom, props)}
                </div>
            );
        }

        return (
            <DropDown
                trigger={TRIGGER.CLICK}
                target={(
                    <div>
                        {this.renderWrapper(textFrom, textTo)}
                    </div>
                )}
                isOpen={isOpen}
                boundaries={POPOVER_BOUNDARIES.DOCUMENT}
                onClose={this.onDropDownClose}
                isDisabled={isDisabled || isReadOnly}
            >
                {this.renderCalendar(dateFrom, dateTo, isFrom, props)}
            </DropDown>
        );
    }
}
