'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {FormControl} from './FormControl';
import {Icon} from '../Icon';
import {DateRange} from 'react-date-range';
import classnames from 'classnames';
import onClickOutside from 'react-onclickoutside';
import moment from 'moment';
import _ from 'lodash';

const ENTER_KEY_CODE = 13;
const SPACE_KEY_CODE = 32;
const ESC_KEY_CODE = 27;

export class DateRangePickerCtrl extends FormControl {
    constructor(props, context) {
        super(props, context);
        this.state = {
            open: false
        };
    }

    static propTypes = {
        ...FormControl.propTypes,
        ranges: PropTypes.object,
        onChange: PropTypes.func,
        startDate: PropTypes.any,
        endDate: PropTypes.any,
        locale: PropTypes.string,
        valueFormatter: PropTypes.func,
        ariaLabel: PropTypes.string,
        setPrevMonthText: PropTypes.string,
        setNextMonthText: PropTypes.string
    };

    static defaultProps = {
        ...FormControl.defaultProps,
        locale: 'en_US',
        value: null,
        valueFormatter: defaultValueFormatter,
        ariaLabel: 'TRANSLATE:CHOOSE_DATE_RANGE',
        setPrevMonthText: 'TRANSLATE:SET_PREV_MONTH',
        setNextMonthText: 'TRANSLATE:SET_NEXT_MONTH'
    };

    getFieldValue(value) {
        if (!value) {
            return moment();
        }
        if (typeof value === 'number') {
            return moment(value);
        }
        if (typeof value === 'string' && moment(value).isValid()) {
            return moment(value);
        }
        if (value instanceof Date) {
            return moment(value);
        }
        return value;
    }

    open = () => {
        this.setState({open: true}, this.addAccessibility);
    };

    close = () => {
        if (this.isDatePickerFocused()) {
            this.refs.input.focus();
        }
        this.removeAccessibility();
        this.setState({open: false});
    };

    closeUnfocused = () => {
        // Wait for changing a focus from input to popover and back
        setTimeout(() => {
            if (this.stopClosing) {
                this.stopClosing = false;
                return;
            }
            if (!this.isInputFocused() && !this.isDatePickerFocused()) {
                this.close();
            }
        }, 50);
    };

    isInputFocused() {
        return document.activeElement === ReactDOM.findDOMNode(this.refs.input);
    }

    isDatePickerFocused() {
        if (!this.state.open) {
            return false;
        }
        let node = ReactDOM.findDOMNode(this.refs.dateRange);
        return !!(node && node.querySelector(':focus'));
    }

    toggle = () => {
        if (this.state.open) {
            this.close();
        } else {
            this.open();
        }
    };

    onDatePickerClick = () => {
        // Prevent close date picker by closeUnfocused method
        this.stopClosing = true;
        setTimeout(() => {
            this.stopClosing = false;
        }, 100);
    };

    addAccessibility = () => {
        let node = ReactDOM.findDOMNode(this.refs.dateRange);
        if (!node) {
            return;
        }

        let {setPrevMonthText, setNextMonthText} = this.props;
        node.addEventListener('mousedown', this.onDatePickerClick);
        node.addEventListener('keyup', this.handleKeyboard);
        node.addEventListener('keydown', this.closeUnfocused);
        _.toArray(
            node.querySelectorAll('.rdr-MonthAndYear-innerWrapper > span, .rdr-WeekDays')
        ).forEach(item => item.setAttribute('role', 'presentation'));

        _.toArray(node.querySelectorAll('.rdr-PredefinedRangesItem')).forEach(item => {
            item.setAttribute('aria-label', item.innerText);
            item.setAttribute('role', 'button');
            item.addEventListener('keydown', e => {
                if (e.keyCode === ENTER_KEY_CODE || e.keyCode === SPACE_KEY_CODE) {
                    setTimeout(this.close, 100);
                }
            });
        });

        _.toArray(node.querySelectorAll('.rdr-MonthAndYear-button.prev')).forEach(item => {
            item.setAttribute('aria-label', setPrevMonthText);
            item.addEventListener('click', this.addDaysAccessibilityAfterChangeMonth);
        });

        _.toArray(node.querySelectorAll('.rdr-MonthAndYear-button.next')).forEach(item => {
            item.setAttribute('aria-label', setNextMonthText);
            item.addEventListener('click', this.addDaysAccessibilityAfterChangeMonth);
        });

        _.toArray(node.querySelectorAll('[tabindex="0"]')).forEach(item => {
            item.addEventListener('blur', this.closeUnfocused);
        });
        this.addDaysAccessibility();
    };

    removeAccessibility = () => {
        let node = ReactDOM.findDOMNode(this.refs.dateRange);
        if (!node) {
            return;
        }
        node.removeEventListener('mousedown', this.onDatePickerClick);
        node.removeEventListener('keyup', this.handleKeyboard);
        _.toArray(node.querySelectorAll('.rdr-MonthAndYear-button.prev')).forEach(item => {
            item.removeEventListener('click', this.addDaysAccessibilityAfterChangeMonth);
        });
        _.toArray(node.querySelectorAll('.rdr-MonthAndYear-button.next')).forEach(item => {
            item.removeEventListener('click', this.addDaysAccessibilityAfterChangeMonth);
        });
        _.toArray(node.querySelectorAll('[tabindex="0"]')).forEach(item => {
            item.removeEventListener('blur', this.closeUnfocused);
        });
    };

    addDaysAccessibility = () => {
        let node = ReactDOM.findDOMNode(this.refs.dateRange);
        if (!node) {
            return;
        }
        _.toArray(node.querySelectorAll('.rdr-Day.is-passive')).forEach(item => {
            item.removeAttribute('tabindex');
            item.removeAttribute('aria-label');
            item.setAttribute('role', 'presentation');
        });
        _.toArray(node.querySelectorAll('.rdr-Day[aria-selected]:not(.is-selected)')).forEach(
            item => {
                item.removeAttribute('aria-selected');
            }
        );
        _.toArray(node.querySelectorAll('.rdr-Day:not(.is-passive)')).forEach(item => {
            item.setAttribute('tabindex', '0');
            item.setAttribute('aria-label', item.innerText);
            item.setAttribute('role', 'button');
        });
        _.toArray(node.querySelectorAll('.rdr-Day.is-selected')).forEach(item => {
            item.setAttribute('aria-selected', 'true');
        });
    };

    addDaysAccessibilityAfterChangeMonth = () => {
        setTimeout(this.addDaysAccessibility, 200);
    };

    handleKeyboard = event => {
        switch (event.keyCode) {
            case ENTER_KEY_CODE:
            case SPACE_KEY_CODE:
                event.target.click();
                break;
            case ESC_KEY_CODE:
                this.close();
                break;
        }
    };

    render() {
        let props = this.getPropsFromContext();
        let disabled = false;

        moment.locale(props.locale);

        let startDate = this.getFieldValue(props.startDate);
        let endDate = this.getFieldValue(props.endDate);

        return (
            <div className={classnames('rc-daterangepicker', {'rc-datepicker-disabled': disabled})}>
                <Icon name="calendar" onClick={this.toggle} />
                <div className="rdt">
                    <input
                        className="form-control"
                        onFocus={this.open}
                        onBlur={this.closeUnfocused}
                        onClick={this.open}
                        onKeyDown={this.handleKeyboard}
                        id={props.id}
                        key="i"
                        type="text"
                        ref="input"
                        readOnly
                        value={this.props.valueFormatter(startDate, endDate)}
                        aria-label={this.props.ariaLabel}
                    />
                    {this.renderDateRange()}
                </div>
            </div>
        );
    }

    renderDateRange() {
        if (this.state.open) {
            let props = this.getPropsFromContext();
            let startDate = this.getFieldValue(props.startDate);
            let endDate = this.getFieldValue(props.endDate);
            return (
                <DateRangeCmp
                    {...props}
                    startDate={startDate}
                    endDate={endDate}
                    handleChange={this.handleChange}
                    ref="dateRange"
                />
            );
        }
        return null;
    }

    handleChange = (which, payload) => {
        if (this.props.onChange) {
            this.props.onChange(payload);
        }
        this.close();
    };

    handleClickOutside = () => {
        this.close();
    };
}

class DateRangeCmp extends React.Component {
    static propTypes = {
        handleChange: PropTypes.func.isRequired
    };

    render() {
        return (
            <DateRange
                {...this.props}
                classNames={{dateRange: 'rdtPicker dropdown-menu'}}
                onlyClasses={true}
                linkedCalendars={true}
                twoStepChange={true}
                onChange={this.props.handleChange.bind(this, 'predefined')}
            />
        );
    }
}

export const DateRangePickerControl = onClickOutside(DateRangePickerCtrl);

function defaultValueFormatter(startDate, endDate) {
    if (startDate.isSame(endDate, 'date')) {
        return startDate.format('L');
    }
    return startDate.format('L') + ' - ' + endDate.format('L');
}
