/* eslint-disable react/jsx-no-bind */
import React from "react";
import classNames from "classnames";
import PropTypes from "prop-types";
import "react-dates/initialize";
import { DayPickerSingleDateController } from "react-dates";
import OutsideClickHandler from "react-outside-click-handler";
import momentPropTypes from "react-moment-proptypes";
import Input from "../Input";
import CalendarNavButton from "./CalendarNavButton";
import { constants } from "./constants";
import { getDateString, getCustomMonthElement, isOutsideAcceptableDateRange } from "./fns";

class DatePicker extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            currentDate: this.props.initialDate,
            currentDateString: getDateString(this.props.initialDate),
            isFocused: this.props.isFocused,
            dayPickerIsOpen: this.props.isFocused || this.props.keepOpenAlways,
        };
    }

    componentDidUpdate(prevProps, prevState) {
        if (prevProps.isFocused !== this.props.isFocused) {
            this.onFocusChange({ focused: this.props.isFocused });
        }
    }

    onFocusChange = ({ focused }) => {
        this.setState({
            isFocused: focused,
            dayPickerIsOpen: focused || this.props.keepOpenAlways,
        });
    };

    onDateChange = date => {
        this.setState({
            currentDate: date,
            currentDateString: getDateString(date),
        });
        this.props.onDateChange && this.props.onDateChange(date);
    };

    onOutsideClick = () => {
        !this.props.keepOpenAlways && this.onFocusChange({ focused: false });
    };

    onClose = () => {
        this.setState({
            dayPickerIsOpen: this.props.keepOpenOnDateSelect || this.props.keepOpenAlways,
        });
    };

    isOutsideAcceptableDateRange = day => {
        const { isOutsideRange, isFutureDateSelectable, isPastDateSelectable } = this.props;
        return isOutsideAcceptableDateRange(day, isOutsideRange, isFutureDateSelectable, isPastDateSelectable);
    };

    onClearButtonClick = () => {
        this.setState({
            currentDateString: "",
            currentDate: null,
        });
    };

    render() {
        const {
            hasClearButton,
            initialVisibleMonth,
            isDisabledInput,
            inputId,
            inputLabel,
            inputPlaceholder,
            isAbsolutelyPositioned,
        } = this.props;
        const { currentDateString, dayPickerIsOpen } = this.state;
        return (
            <OutsideClickHandler onOutsideClick={this.onOutsideClick}>
                <div className={classNames("oui-date-picker", isAbsolutelyPositioned && "oui-date-picker--absolute")}>
                    <div className="oui-date-picker__input-row">
                        <Input
                            hasClearButton={hasClearButton}
                            isDisabled={isDisabledInput}
                            id={inputId}
                            isReadOnly={true}
                            label={inputLabel}
                            name="date-picker"
                            onBlur={this.onBlur}
                            onClearButtonClick={this.onClearButtonClick}
                            onFocus={this.onFocusChange.bind(this, { focused: true })}
                            placeholder={inputPlaceholder}
                            type="text"
                            value={currentDateString}
                        />
                    </div>
                    {dayPickerIsOpen && (
                        <DayPickerSingleDateController
                            date={this.state.currentDate}
                            daySize={constants.DAY_SIZE}
                            focused={this.state.isFocused}
                            hideKeyboardShortcutsPanel={true}
                            initialVisibleMonth={initialVisibleMonth}
                            isOutsideRange={this.isOutsideAcceptableDateRange}
                            navNext={<CalendarNavButton type="next" />}
                            navPrev={<CalendarNavButton type="previous" />}
                            numberOfMonths={constants.SINGLE_NUM_MONTHS}
                            onClose={this.onClose}
                            onDateChange={this.onDateChange}
                            onFocusChange={this.onFocusChange}
                            phrases={constants.PHRASES}
                            renderMonthElement={getCustomMonthElement}
                            transitionDuration={constants.TRANSITION_DURATION}
                        />
                    )}
                </div>
            </OutsideClickHandler>
        );
    }
}

DatePicker.propTypes = {
    /** Whether or not to add a clear button to right of input */
    hasClearButton: PropTypes.bool,
    /** An initial date to populate the input with, must be a moment() */
    initialDate: momentPropTypes.momentObj,
    /** Function to determine what month the date picker
     *  should show on the left hand side
     */
    initialVisibleMonth: PropTypes.func,
    /** The id of the input, used to associate with a label */
    inputId: PropTypes.string.isRequired,
    /** The label text above the input */
    inputLabel: PropTypes.string,
    /** The text to use as the placeholder of the label */
    inputPlaceholder: PropTypes.string,
    /** When true, opens the calendar on top of other elements on the page */
    isAbsolutelyPositioned: PropTypes.bool,
    /** If true, disables the input */
    isDisabledInput: PropTypes.bool,
    /** Determines if the input is currently focused or not  */
    isFocused: PropTypes.bool,
    /** Determines if the user can choose a date in the future  */
    isFutureDateSelectable: PropTypes.bool,
    /**
     * Custom function to determine if a date is outside the acceptable range.
     * Function is called for each visible day, with a moment() object
     * passed as the first parameter.
     */
    isOutsideRange: PropTypes.func,
    /** Determines if the user can choose a date in the past  */
    isPastDateSelectable: PropTypes.bool,
    /**
     * Determines if the calendar remains open no matter
     * where the user clicks on the page
     */
    keepOpenAlways: PropTypes.bool,
    /** Determines if the calendar should stay
     * open when a date has been selected,
     * but close when user clicks away
     */
    keepOpenOnDateSelect: PropTypes.bool,
    /** Function callback to perform when a date has been selected.
     * The date selected is passed as a parameter.
     * Use React.createRef(); to get access to this component's
     * onDateChange method and set it from a parent
     */
    onDateChange: PropTypes.func,
};

DatePicker.defaultProps = {
    inputLabel: "Select Date",
    inputPlaceholder: "Select Date",
    inputId: "date-input-01",
    isAbsolutelyPositioned: false,
    isFutureDateSelectable: true,
    isPastDateSelectable: true,
    keepOpenAlways: false,
    keepOpenOnDateSelect: false,
};

export default DatePicker;
