import React, { FC, forwardRef, useCallback, useEffect, useRef, useState } from "react";
import Datepicker, { registerLocale } from 'react-datepicker';
import moment from "moment";
import cx from 'classnames';
import { Icons } from "../../Icons"; 
import { TimePicker } from "../TimePicker";
import AreaMenu, {Area, Menu} from '../../AreaMenu';
import { Button } from "../../Button";

import '../style.scss'
import { DateRangeProps } from "./DateRangePicker.types"

//react-datepicker change useIntl() (locale) for date-fns and need to register
import en from 'date-fns/locale/en-US'; 
import es from 'date-fns/locale/es';
import { useCurrentLang } from "../../../hooks/useLocale";

registerLocale('en', en);
registerLocale('es', es);

export const DateRangePicker: FC<DateRangeProps> = ({
    id, 
    startDate = new Date().toISOString(), 
    endDate = "", 
    format = 'MMM DD, YYYY', 
    showButtons = false, 
    onChange, 
    className, 
    withTime = false, 
    maxDate,
    minDate = "",
    orientation = "horizontal",
    calendarPosition = "bottom",
    style,
    customRangeDate,
    isCompleted
}) => {
    const locale = useCurrentLang()
    const [dateStartValue, setDateStartValue] = useState<moment.Moment>(startDate && moment(startDate) || moment())
    const [dateEndValue, setDateEndValue] = useState<moment.Moment | null>(endDate && moment(endDate) || moment().endOf("day"))

    const [startTimeValue, setStartTimeValue] = useState<moment.Moment>(startDate && moment(startDate)|| moment().set({"hour": 0, "minute": 0, "second": 0}) )
    const [endTimeValue, setEndTimeValue] = useState<moment.Moment>(endDate && moment(endDate) || moment().set({"hour": 23, "minute": 59, "second": 59}) )
    const [selectionDate, setSelectionDate] = useState<string>(startDate && !endDate ? "end" : "start") 

    const areaMenuRef = useRef<any>()

    let inputSize = {minWidth: "202px"}
    let menuSize = {width: "490px", right: "", left: "0"}
    let buttonSize = {width: "235px", height: "36px"}

    if (withTime){
        format = 'MMM DD, YYYY hh:mm A'
        inputSize = {minWidth: "322px"}
    }

    if (orientation === "vertical"){
        menuSize = {width: "240px", right: "", left: "0"}
        buttonSize = {width: "111px", height: "30px"}
    }

    let newMaxDate: moment.Moment | undefined = maxDate ? moment(maxDate) : moment()


    if(customRangeDate && dateStartValue){
        if(dateStartValue?.clone()?.add(customRangeDate - 1 , 'days').isAfter(moment().endOf('day'))){
          const limitDate:moment.Moment | undefined = dateStartValue?.clone().endOf('day').add(customRangeDate, 'days')
          newMaxDate = newMaxDate?.isAfter(limitDate) ? limitDate : newMaxDate;
  
        }else{
          newMaxDate = dateStartValue?.clone()?.add(customRangeDate - 1, 'days').endOf("day");
          if (dateEndValue && dateEndValue.isAfter(newMaxDate)){
              setDateEndValue(null)
              setSelectionDate("end")
          }
        }
      }

    const handleStartTimeChange = (datetime: any, momentTime: any) => {
        let newDate = dateStartValue.clone()
        newDate.set({
            'hour': momentTime.hours(), 
            'minute': momentTime.minutes()
        })
        setDateStartValue(newDate)
        setStartTimeValue(momentTime)

        //onChange && onChange(tempDate.toDate(), tempDate)
    }

    const handleEndTimeChange = (datetime: any, momentTime: any) => {
        let newDate = dateEndValue ? dateEndValue.clone() : moment()
        newDate.set({
            'hour': momentTime.hours(), 
            'minute': momentTime.minutes()
        })
        setDateEndValue(newDate)
        setEndTimeValue(momentTime)
    }

    const saveInfoOnClose= () => {
        if(dateStartValue?.toDate() && dateEndValue?.toDate() && onChange){
            onChange(dateStartValue?.toDate(), dateEndValue?.toDate(), dateStartValue, dateEndValue)
        } else if(dateStartValue?.toDate() && onChange){
            const dateEnd = dateStartValue.clone()?.endOf('day')
            onChange(dateStartValue?.toDate(), dateEnd?.toDate(), dateStartValue, dateEnd)
        }
    }
    
    function capitalize(str: string | undefined) {
        if (str)
            return (str.charAt(0).toUpperCase() + str.slice(1)).replace('.','');
    }

    return (
        <AreaMenu
            id={id || "datepicker"} 
            menuPlacement={calendarPosition}  
            ref={areaMenuRef}
        >
            <Area>
                <div className={cx("gtc-rc-datepicker_area", className)} style={{...inputSize, ...style}}>
                    <input 
                        data-testid="DateRangePickerInput"
                        style={{...inputSize, ...style}}
                        className="gtc-rc-datepicker_input" 
                        value={`${capitalize(dateStartValue.locale(locale).format(format)) || ''} - ${capitalize(dateEndValue?.locale(locale).format(format))|| ''}`} 
                        //onClick={saveInfoOnClose}
                        readOnly 
                        spellCheck={false}
                    />
                    <Icons  className="gtc-rc-datepicker_icon"  name={"calendar_month"} size="small" />
                </div>
            </Area>
            <Menu>
                <div className={cx("gtc-rc-daterangepicker_menu", `gtc-rc-daterangepicker_menu_${orientation}`)} style={menuSize}>        
                    <Datepicker
                        selected={dateStartValue?.toDate()}
                        inline
                        startDate={dateStartValue?.toDate()}
                        endDate={dateEndValue?.toDate()}
                        monthsShown={2}
                        selectsRange
                        maxDate={newMaxDate?.toDate()}
                        minDate={minDate ? new Date(moment(minDate).format(format)) : undefined}
                        onChange={(newDates) => {
                            const [start, end] = newDates;
                            let newStart
                            let newEnd

                            if (withTime) {
                            newStart = start && start.setHours(startTimeValue.hours()) && start.setMinutes(startTimeValue.minutes())
                            newEnd = end && end.setHours(endTimeValue.hours()) && end.setMinutes(endTimeValue.minutes())
                            } else {
                                newStart =  start &&  start.setHours(0) && start.setMinutes(0) && start.setSeconds(0)
                                newEnd = end && end.setHours(23) && end.setMinutes(59) && end.setSeconds(59)
                            }

                            if(isCompleted){
                                let completed = !start || !end ? false : true
                                isCompleted(completed)
                            }

                            setDateStartValue(moment(newStart))
                            setDateEndValue(newEnd ? moment(newEnd): null)
                        }}
                        locale={locale}

                    />
                    { withTime && dateEndValue &&
                        <div className="gtc-rc-datepicker_container_range_time">
                            <div className="gtc-rc-time_container">
                                <TimePicker variant="inputs" value={startTimeValue} onChange={handleStartTimeChange}/>
                            </div>
                            {orientation === "horizontal" && 
                                <div className="gtc-rc-time_container">
                                    <TimePicker variant="inputs" value={endTimeValue} onChange={handleEndTimeChange}/>
                                </div>
                            }

                        </div>
                    }
                    { showButtons &&
                        <div className="gtc-rc-datepicker_buttons_container">
                            <Button
                                style={buttonSize}
                                size="small"
                                variant="secondary"
                                onClick={() => {
                                    setDateStartValue(startDate && moment(startDate) || moment())
                                    setDateEndValue(endDate && moment(endDate) || null)
                                    areaMenuRef.current?.close()
                                }}
                            >
                                {"cancel"}
                            </Button>
                            <Button
                                isDisabled={!dateStartValue || !dateEndValue}
                                style={buttonSize}
                                size="small"
                                variant="primary"
                                onClick={() => {
                                    saveInfoOnClose()
                                    areaMenuRef.current?.close()
                                }}
                            >
                                {"apply_lang"}
                            </Button>
                        </div>
                    }
                </div>
            </Menu>
        </AreaMenu>
    )
}
