import React from 'react';
import PropTypes from 'prop-types';
import {TextInputControl} from '../TextInputControl';
import _ from 'lodash';
import {DayPickerRangeController} from 'react-dates';
import {
    dateRangePickerValueFormatter,
    isSameDate,
    REACT_DATES_START_DATE_INPUT_MODE
} from './datePickerHelpers';
import moment from 'moment';
import {PreDefinedRangesBlock} from './PreDefinedRangesBlock';
import {DatePickerBase} from './DatePickerBase';
import {renderCalendarDayContent} from './renderCalendarDayContent';
import lang from '../../../../lang/common/index-en_US';

export class DayRangePickerControl extends DatePickerBase {
    static propTypes = {
        ...TextInputControl.propTypes,
        ...DatePickerBase.propTypes,

        startDate: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
        endDate: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),

        valueFormatter: PropTypes.func,
        onChange: PropTypes.func,
        numberOfMonths: PropTypes.number,

        dayPickerProps: PropTypes.object,
        inputProps: PropTypes.object,
        ranges: PropTypes.object,

        maxDate: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
        minDate: PropTypes.oneOfType([PropTypes.number, PropTypes.object])
    };

    static defaultProps = {
        ...TextInputControl.defaultProps,
        ...DatePickerBase.defaultProps,
        testAutomationId: 'dayRangePicker',

        startDate: null,
        endDate: null,

        valueFormatter: dateRangePickerValueFormatter,

        dayPickerProps: {},
        numberOfMonths: 2,
        inputProps: {},
        ranges: null,
        maxDate: null,
        minDate: null,
        get ariaLabel() {
            return lang.CHOOSE_DATE_RANGE;
        }
    };

    state = {
        ...super['state'],
        startDate: this.props.startDate,
        endDate: this.props.endDate,
        focusedInput: REACT_DATES_START_DATE_INPUT_MODE,
        value: this.getPropsFromContext().value
    };

    componentWillReceiveProps(newProps) {
        const {startDate: newStartDate, endDate: newEndDate} = newProps;
        const {startDate, endDate} = this.props;

        const newStates: any = {};
        if (!isSameDate(startDate, newStartDate)) {
            newStates.startDate = newStartDate;
        }

        if (!isSameDate(endDate, newEndDate)) {
            newStates.endDate = newEndDate;
        }

        if (!_.isEmpty(newStates)) {
            this.setState(newStates);
        }
    }

    onCalendarFocusChange = focusedInput => this.setState({focusedInput});

    notifyDateTimeChange = ({startDate, endDate: endDateValue}) => {
        let {onChange: onChangeFromContext} = this.getPropsFromContext();
        let {onChange: onChangeFromProp} = this.props;
        let endDate = endDateValue === null ? startDate : endDateValue;

        if (_.isFunction(onChangeFromProp)) {
            onChangeFromProp({startDate, endDate});
        } else if (_.isFunction(onChangeFromContext)) {
            onChangeFromContext({startDate, endDate});
        }
    };

    onDatesChange = ({startDate, endDate}) => {
        this.setState({startDate, endDate}, () => this.notifyDateTimeChange({startDate, endDate}));
    };

    onPredefinedRangeButtonClick = ({startDate, endDate}) => {
        this.onDatesChange({startDate, endDate});
        this.closeDayPicker();
        this.toggleIsInputFocusedFromOutside(false);
        this.focusToInput();
    };

    renderPredefinedRanges = () => {
        const {ranges} = this.props;
        const {startDate, endDate} = this.state;

        return (
            <PreDefinedRangesBlock
                ranges={ranges}
                startDate={startDate}
                endDate={endDate}
                onPredefinedRangeButtonClick={this.onPredefinedRangeButtonClick}
            />
        );
    };

    isOutsideRange = dayValue => {
        const day = moment(dayValue).startOf('date');
        const {maxDate, minDate} = this.props;

        const maxDateMoment = maxDate ? moment(maxDate) : maxDate;
        const minDateMoment = minDate ? moment(minDate) : minDate;

        if (maxDateMoment && minDateMoment) {
            return moment(minDateMoment).isAfter(day) || moment(maxDateMoment).isSameOrBefore(day);
        }

        if (maxDateMoment) {
            return moment(maxDateMoment).isBefore(day);
        }

        if (minDateMoment) {
            return moment(minDateMoment).isAfter(day);
        }

        return false;
    };

    handleCloseDayPicker = dateRange => {
        const {focusedInput} = this.state;
        this.toggleIsInputFocusedFromOutside(false);
        this.closeDayPicker();
        this.setState({focusedInput: REACT_DATES_START_DATE_INPUT_MODE});
        if (!_.isEmpty(dateRange)) {
            this.onDatesChange(dateRange);
        }

        if (focusedInput !== REACT_DATES_START_DATE_INPUT_MODE) {
            this.focusToInput();
        }
    };

    /**@override*/
    closeDayPicker() {
        this.setState({
            focusedInput: REACT_DATES_START_DATE_INPUT_MODE
        });
        return super.closeDayPicker();
    }

    /** @override */
    getDisplayValue = () => {
        const {startDate, endDate} = this.state;
        const {valueFormatter} = this.props;

        if (_.isEmpty(startDate) || _.isEmpty(endDate)) {
            return '';
        }

        return valueFormatter(startDate, endDate);
    };

    /** @override */
    renderDatePicker: any = () => {
        const {numberOfMonths, dayPickerProps} = this.props;
        const {startDate, endDate, focusedInput, isDayPickerFocused, isDayPickerVisible} = this
            .state as any;

        if (!isDayPickerVisible) {
            return null;
        }

        return (
            <DayPickerRangeController
                isFocused={isDayPickerFocused}
                focusedInput={focusedInput}
                numberOfMonths={numberOfMonths}
                onFocusChange={this.onCalendarFocusChange}
                onDatesChange={this.onDatesChange}
                onClose={this.handleCloseDayPicker}
                startDate={startDate}
                endDate={endDate}
                renderCalendarInfo={this.renderPredefinedRanges}
                isOutsideRange={this.isOutsideRange}
                calendarInfoPosition="before"
                hideKeyboardShortcutsPanel
                phrases={this.getPhrases()}
                renderDayContents={renderCalendarDayContent}
                minimumNights={0}
                {...dayPickerProps}
            />
        );
    };
}
