import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import shortid from 'shortid';
import classNames from 'classnames';
import moment from 'moment'

import {validations, getValidator} from '../../helpers/helpers';

import findParentForm from '../../helpers/findParentForm';
import Icon from '../../components/Icon';

import iconDown from './assets/icons/caret-down.svg'
import iconLeft from './assets/icons/left-arrow.svg'
import iconRight from './assets/icons/right-arrow.svg'
import iconDot from './assets/icons/circle.svg'

@findParentForm
export default class Date extends Component {
    id = shortid();

    static defaultProps = {
        timeFormat: 'HH:mm',
        intervals: 15,
        time: false
    };

    constructor(props) {
        super(props);
        let {value} = props;
        let defaultDate = value || Date.now

        this.state = {
            focus: false,
            error: null,
            success: null,
            value: value && moment(defaultDate),
            calendarValue: moment(defaultDate),

            dateValue: moment(defaultDate),
            timeValue: moment(defaultDate),
            showYears: false,
        }
    }

    get _value() {
        return this.state.value
    }

    get _isHasValue() {
        let {value} = this.state;
        return value && value.isValid()
    }

    get format() {
        let {format, time} = this.props;
        if (format)
            return format;
        return time ? 'LLL' : 'LL';
    }

    get calendarValue() {
        let {value, calendarValue} = this.state;
        let date = null;
        if (value && value.isValid()) {
            date = value;
        }
        {
            date = calendarValue;
        }

        return date.clone();
    }

    set(value) {
        this.input.value = value.format(this.format);
        // if (this.props.onChange) {
        //     this.props.onChange(value);
        // }
    }

    __handleClick = (e) => {
        if (
            this.state.focus &&
            e.target !== this.input &&
            e.target !== this.datePicker &&
            !this.field.contains(e.target) &&
            !this.datePicker.contains(e.target)
        ) {
            this.__onBlur()
        }
    };

    componentDidUpdate(prevProps, prevState) {
        if (
            this.state.value &&
            prevState.value &&
            !this.state.value.isValid() &&
            prevState.value.isValid()
        ) {
            this.prevValidValue = prevState.value;
        }
    }

    componentDidMount() {
        if (typeof document !== "undefined") {
            document.body.addEventListener('click', this.__handleClick, true)
        }
        if(this.state.value){
            this.input.value = this.state.value.format(this.format)
        }
    }

    componentWillUnmount() {
        if (typeof document !== "undefined") {
            document.body.removeEventListener('click', this.__handleClick, true)
        }
    }

    validate() {
        let {_value: value} = this;
        let {validate} = this.props;
        let promises = [];
        if (value && !value.isValid()) {
            this.setState({success: false, error: 'Invalid date'});
            return Promise.reject('Invalid date');
        }

        if (!validate) {
            this.setState({success: true, error: null});
            return Promise.resolve(value);
        } else if ({}.toString.call(validate) === '[object Function]') {
            promises.push(validate(value));
        } else {
            for (let key in validate) {
                let valid = null;
                let error = validate[key].error || 'ERROR';
                if (validate[key].custom) {
                    valid = validate[key].custom(value);
                } else {
                    let validator = getValidator(key);
                    valid = validations[validator.name](value, ...validator.args);
                }
                if (valid) {
                    promises.push(Promise.resolve())
                } else {
                    promises.push(Promise.reject(error));
                    break;
                }
            }
        }
        return Promise.all(promises).then(() => {
            this.setState({success: true, error: null});
            return Promise.resolve(value);
        }).catch((error) => {
            this.setState({success: null, error});
            return Promise.reject(error);
        })
    }

    __setValue(value) {
        this.setState({value: moment(value)})
    }

    __onFocus = () => {
        this.setState({focus: true})
    };

    __onBlur = () => {
        let {_value: value} = this;
        let {time, onChange} = this.props;

        if (value && value.isValid()) {
            this.input.value = value.format(this.format);
        }
        if (this.props.onBlur) {
            this.props.onBlur();
        }
        this.setState({
            focus: false, showYears: false,
        });
        this.validate();

        if (onChange) {
            onChange(value);
        }
    };

    __onChange = (e) => {
        let {onChange} = this.props;
        let date = null;
        if (e.target.value) {
            date = moment(e.target.value).format(this.format);
        } else {
            date = null;
        }

        this.setState({value: date});
        if (this.state.error) {
            this.setState({error: null})
        }
        if (onChange) {
            onChange(date);
        }
    };

    __getPositionsForDatePicker = () => {
        let selectRect = this.input.getBoundingClientRect();
        let {portal} = this.props;
        let left = 0, top = '100%';
        if(portal){
            left = selectRect.left + pageXOffset;
            top = selectRect.top + selectRect.height + pageYOffset;
        }
        return {
            position: 'absolute',
            left,
            top
        }
    };

    __renderDaysForDatePicker() {
        let {value, calendarValue} = this.state;
        let {time} = this.props;

        let currentDate = moment();

        const isHasValue = value && value.isValid();


        let daysInMonth = calendarValue.daysInMonth();
        let startDay = calendarValue.clone().date(1).day();
        let calendarStart = 1 - startDay;
        let countDays = daysInMonth + startDay;
        let calendarEnd = daysInMonth + 7 - ((countDays % 7) || 7);

        let days = [];

        for (let i = calendarStart; i <= calendarEnd; i++) {
            let isNotThisMonth = i < 1 || i > daysInMonth;
            let day = moment(calendarValue).date(i);
            let isCurrentDay = false;
            let isSelected = false;

            if (
                !isNotThisMonth &&
                day.isSame(currentDate, 'day') &&
                day.isSame(currentDate, 'year')
            ) {
                isCurrentDay = true;
            }
            if (
                isHasValue &&
                value.isSame(day, 'day') &&
                value.isSame(day, 'month') &&
                value.isSame(day, 'year')
            ) {
                isSelected = true;
            }

            days.push(
                <div
                    key={i}
                    className={classNames({
                        'sbxFormField__datePickerDay': true,
                        'sbxFormField__datePickerDay_selected': isSelected,
                        'sbxFormField__datePickerDay_currentDay': isCurrentDay,
                        'sbxFormField__datePickerDay_notSelectedMonth': isNotThisMonth,
                    })}
                    onClick={e => {
                        console.log(day.clone().format(this.format));
                        this.setState({value: day.clone(), calendarValue: day.clone()}, () => {
                            this.set(day.clone());

                            // if (!time)
                            //     this.__onBlur();

                        })
                    }}
                >
                    {day.format('D')}
                </div>
            )
        }
        return days;
    }

    renderTimes = () => {
        let {intervals, timeFormat} = this.props;
        let {value, calendarValue} = this.state;

        const isHasValue = value && value.isValid();

        const multiplier = 1440 / intervals;

        let times = [];
        let base = moment(calendarValue).startOf('day');


        console.log(base.format(this.format));

        for (let i = 0; i < multiplier; i++) {
            const currentTime = moment(base).add(i * intervals, 'minutes');
            times.push(currentTime);
        }

        return times.map((time, i) => {
            let isSelected = false;
            if (
                isHasValue &&
                value.isSame(time, 'minutes') &&
                value.isSame(time, 'hours')
            ) {
                isSelected = true;
            }
            return <li
                key={i}
                className={classNames({
                    'sbxFormField__datePickerTimesListItem': true,
                    'sbxFormField__datePickerTimesListItem_selected': isSelected,
                })}
                onClick={e => {
                    this.setState({value: time}, () => {
                       // this.__onBlur();
                        this.set(time);
                    })
                }}
            >
                {time.format(timeFormat)}
            </li>
        });
    };

    renderYears = () => {
        let {value, calendarValue} = this.state;
        let selectedYear = calendarValue.year();
        let selectedMonth = calendarValue.month();

        const isHasValue = value && value.isValid();

        let years = [];

        for (let year = 1800; year <= 2200; year++) {
            let isSelected = year === selectedYear;
            years.push(
                <div
                    key={year}
                    ref={e => {
                        if (e && isSelected) {
                            e.focus();
                        }
                    }}
                    tabIndex={0}
                    className="sbxFormField__datePickerYearsItem"
                >
                    <div
                        className={classNames({
                            'sbxFormField__datePickerYear': true,
                            'sbxFormField__datePickerYear_selected': isSelected,
                        })}
                        onClick={e => {
                            this.setState({
                                [isHasValue ? 'value' : 'calendarValue']: calendarValue.set('year', year),
                            })
                        }}
                    >
                        {year}
                    </div>
                    {isSelected && <div className="sbxFormField__datePickerMonths">
                        {moment.monthsShort().map((month, index) => {
                            let isSelectedMonth = index === selectedMonth;
                            return <div
                                key={month}
                                className={classNames({
                                    'sbxFormField__datePickerMonth': true,
                                    'sbxFormField__datePickerMonth_selected': isSelectedMonth
                                })}
                                onClick={e => {
                                    this.setState({
                                        [isHasValue ? 'value' : 'calendarValue']: calendarValue.set('month', index),
                                        showYears: false
                                    });
                                }}
                            >
                                {month}
                            </div>
                        })}
                    </div>}
                </div>
            )
        }

        return <div
            className="sbxFormField__datePickerYears"
        >
            {years}
        </div>
    };

    renderDatePciker = (children) => {
        let {portal} = this.props;
        if(portal)
            return ReactDOM.createPortal(children, document.body);
        return children
    };

    render() {
        let {error, success, focus, showYears, calendarValue} = this.state;
        let {
            label,
            time,
            className,
            name,
            readOnly
        } = this.props;

        let props = {...this.props};

        delete props.value;
        delete props.validate;
        delete props.intervals;
        delete props.time;



        return <div ref={e => this.field = e} className="sbxFormField">
            {label && <label
                htmlFor={this.id}
                className="sbxFormField__label"
            >
                {label}
            </label>}
            <input
                placeholder={props.placeholder}
                id={this.id}
                name={name}
                readOnly={true}
                ref={e => this.input = e}
                onFocus={this.__onFocus}
                onChange={this.__onChange}
                className={classNames({
                    'sbxFormField__input': true,
                    'sbxFormField__input_invalid': error,
                    'sbxFormField__input_valid': success,
                    'sbxFormField__input_focus': focus,
                    [className]: !!className
                })}
            />
            {focus && this.renderDatePciker(
                <div
                className="sbxFormField__datePicker"
                ref={e => this.datePicker = e}
                style={this.__getPositionsForDatePicker()}
            >
                <div className="sbxFormField__datePickerHeader">
                    <div
                        className="sbxFormField__datePickerButtonSelect"
                        onClick={e => {
                            this.setState({showYears: !showYears})
                        }}
                    >
                        {calendarValue.format('MMMM YYYY')}
                        <Icon
                            src={iconDown}
                        />
                    </div>
                    <div className="sbxFormField__datePickerControls">
                        <div
                            className="sbxFormField__datePickerControlButton"
                            onClick={e => {
                                this.setState({
                                    calendarValue: calendarValue.add('month', -1),
                                    showYears: false
                                })
                            }}
                        >
                            <Icon
                                src={iconLeft}
                            />
                        </div>
                        <div
                            className="sbxFormField__datePickerControlButton"
                            onClick={e => {
                                this.setState({
                                    value: moment(),
                                    calendarValue: moment(),
                                    showYears: false
                                }, () => {
                                    if (!time)
                                        this.__onBlur();
                                })
                            }}
                        >
                            <Icon src={iconDot}/>
                        </div>
                        <div
                            className="sbxFormField__datePickerControlButton"
                            onClick={e => {
                                this.setState({
                                    calendarValue: calendarValue.add('month', 1),
                                    showYears: false
                                })
                            }}
                        >
                            <Icon
                                src={iconRight}
                            />
                        </div>
                    </div>
                </div>
                <div className="sbxFormField__datePickerBody">
                    {showYears && this.renderYears()}
                    {!showYears && <React.Fragment>
                        <div className="sbxFormField__datePickerCalendar">
                            <div className="sbxFormField__datePickerWeekdays">
                                {moment.weekdaysMin().map(day => {
                                    return <div
                                        className="sbxFormField__datePickerWeekdaysDay"
                                        key={day}
                                    >
                                        {day}
                                    </div>
                                })}
                            </div>
                            <div className="sbxFormField__datePickerDays">
                                {this.__renderDaysForDatePicker()}
                            </div>
                        </div>
                        {time && <div
                            className="sbxFormField__datePickerTimes"
                        >
                            <div className="sbxFormField__datePickerTimesHeader">
                                Time
                            </div>
                            <div className="sbxFormField__datePickerTimesListWrap">
                                <ul
                                    className="sbxFormField__datePickerTimesList"
                                >
                                    {this.renderTimes()}
                                </ul>
                            </div>
                        </div>}
                    </React.Fragment>}
                </div>
            </div>
                , document.body)}
            {error && <div
                className='sbxFormField__invalidFeedback'
            >
                {error}
            </div>}
        </div>
    }
}
