import "../../../../src/components/pagination/pagination.sass";
import "../../../../src/components/dropdown/dropdown.sass";
import "../../../../src/components/form/datepicker/datepicker.sass";
import { useDisable, UseDisablePropsDefinition } from '../../../composables/disable';
import { useEqRef } from '../../../composables/eqRef';
import { useFieldData } from '../../../composables/fieldData';
import { getUseInputPropsDefinition } from '../../../composables/input/useInput';
import { useProxy } from '../../../composables/proxy/useProxy';
import { DEFAULT_DAY_NAMES, DEFAULT_MONTH_NAMES } from './shared';
import { addDays, eqSerialDate, isDate } from './utils';
import { BInput } from '../input/BInput';
import { isArrowDownEvent, isArrowLeftEvent, isArrowRightEvent, isArrowUpEvent, isEnterEvent, isEscEvent, isSpaceEvent } from '../../../utils/eventHelpers';
import { head, isNonEmpty, range } from 'fp-ts/lib/Array';
import { constant } from 'fp-ts/lib/function';
import { alt, chain, fromNullable, getEq, isNone, isSome, some } from 'fp-ts/lib/Option';
import { pipe } from 'fp-ts/lib/pipeable';
import BDropdown, { BDropdownPropsDefinition } from '../../dropdown/BDropdown';
import BDatepickerTable from './BDatepickerTable';
import BField from '../field/BField';
import { BSelect } from '../select/BSelect';
import { computed, onUnmounted, onMounted, defineAsyncComponent, defineComponent, h, shallowRef, watch, toRef } from 'vue';
import { constEmptyArray, isString, toggleListItem } from '../../../utils/helpers';
const DEFAULT_DATEPICKER_ICONS = {
  previous: defineAsyncComponent(() => import('../../icons/angleLeft')),
  next: defineAsyncComponent(() => import('../../icons/angleRight')),
  calendar: defineAsyncComponent(() => import('../../icons/calendar'))
};
export function getDatepickerIcons(icons) {
  return { ...DEFAULT_DATEPICKER_ICONS,
    ...icons
  };
}
const BDatepickerPropsDefinition = { ...BDropdownPropsDefinition,
  ...UseDisablePropsDefinition,
  ...getUseInputPropsDefinition(),
  modelValue: {
    type: [Array, Date]
  },
  'onUpdate:modelValue': {
    type: Function,
    required: true
  },
  year: {
    type: Number,
    default: new Date().getFullYear()
  },
  'onUpdate:year': {
    type: Function,
    required: false
  },
  month: {
    type: Number,
    default: new Date().getMonth()
  },
  'onUpdate:month': {
    type: Function,
    required: false
  },
  dayNames: {
    type: Array,
    default: constant(DEFAULT_DAY_NAMES)
  },
  monthNames: {
    type: Array,
    default: constant(DEFAULT_MONTH_NAMES)
  },
  firstDayOfWeek: {
    type: Number,
    default: 0
  },
  events: {
    type: Array,
    default: constEmptyArray
  },
  minDate: {
    type: Date,
    required: false
  },
  maxDate: {
    type: Date,
    required: false
  },
  isDisabled: {
    type: Boolean,
    default: false
  },
  unselectableDates: {
    type: Array,
    default: constEmptyArray
  },
  unselectableDaysOfWeek: {
    type: Array,
    default: constEmptyArray
  },
  selectableDates: {
    type: Object
  },
  showWeekNumber: {
    type: Boolean,
    default: false
  },
  isMultiple: {
    type: Boolean,
    default: false
  },
  placeholder: {
    type: String
  },
  useMobileNative: {
    type: Boolean,
    default: false
  },
  position: {
    type: String
  },
  indicators: {
    type: String,
    default: 'bars'
  },
  yearsRange: {
    type: Array,
    default: constant([-5, 3])
  },
  closeOnSelect: {
    type: Boolean,
    default: true
  },
  isReadonly: {
    type: Boolean,
    default: true
  },
  useNativeValidation: {
    type: Boolean,
    default: false
  },
  // openOnFocus: {
  //   type: Boolean as PropType<boolean>,
  //   default: true
  // },
  icons: {
    type: Object,
    default: constant(DEFAULT_DATEPICKER_ICONS)
  }
};

function useNative(props) {
  return props.useMobileNative && !props.isInline;
}

const useFormattedDate = Intl.DateTimeFormat('default', {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric'
}).format;

function useFormattedModelValue(modelValue) {
  return Array.isArray(modelValue) ? modelValue.map(useFormattedDate).join(', ') : modelValue ? useFormattedDate(modelValue) : null;
}

function parseInputString(str) {
  const splits = str.split(',').map(s => s.trim());
  return splits.map(s => new Date(s)).filter(d => isDate(d) && !isNaN(d.getTime()));
}

function generateInput(props, context, data) {
  const isMobile = useNative(props);
  return h(BInput, {
    max: props.maxDate ? useFormattedDate(props.maxDate) : null,
    min: props.minDate ? useFormattedDate(props.minDate) : null,
    autocomplete: 'off',
    type: isMobile ? 'date' : 'text',
    modelValue: useFormattedModelValue(data.modelValue.value),
    'onUpdate:modelValue': val => {
      data.modelValue.value = parseInputString(val);
    },
    placeholder: props.placeholder,
    size: props.size,
    icon: props.icons.calendar,
    isRounded: props.isRounded,
    isDisabled: props.isDisabled,
    isReadonly: props.isReadonly,
    isLoading: props.isLoading,
    useNativeValidation: props.useNativeValidation // onFocus: () => {
    //   if (!isMobile && props.openOnFocus && toggle) {
    //     if (toggle.isOff.value) {
    //       console.log('focus-set-on')
    //       toggle.setOn();
    //       Date.now()
    //     }
    //   }
    // }

  });
}

function generateButton(props, data, isNext) {
  return h('button', {
    class: isNext ? 'pagination-next datepicker-next' : 'pagination-previous datepicker-previous',
    disabled: data.isDisabled,
    onClick: isNext ? data.nextMonth : data.previousMonth,
    onKeydown: e => {
      if (isEnterEvent(e) || isSpaceEvent(e)) {
        e.preventDefault();
        isNext ? data.nextMonth() : data.previousMonth();
      }
    }
  }, [h(isNext ? props.icons.next : props.icons.previous, {
    variant: 'is-link',
    isThemeable: false
  })]);
}

function generateYearSelect(props, data) {
  return h(BSelect, {
    items: data.years,
    modelValue: data.year.value,
    isDisabled: data.isDisabled,
    size: props.size,
    'onUpdate:modelValue': data.setYear
  });
}

function generateMonthSelect(props, data) {
  return h(BSelect, {
    items: data.months,
    isDisabled: data.isDisabled,
    size: props.size,
    modelValue: data.month.value,
    'onUpdate:modelValue': data.setMonth
  });
}

function generateSelects(props, data) {
  return h('div', {
    class: 'pagination-list'
  }, [h(BField, {
    class: 'is-marginless'
  }, () => [generateMonthSelect(props, data), generateYearSelect(props, data)])]);
}

function generateDefaultHeaderContents(props, data) {
  return h('div', {
    class: ['pagination field is-centered', props.size]
  }, [generateButton(props, data, false), generateSelects(props, data), generateButton(props, data, true)]);
}

function generateHeader(props, context, data) {
  return h('header', {
    class: 'datepicker-header'
  }, context.slots.header ? context.slots.header(data) : [generateDefaultHeaderContents(props, data)]);
}

function generateDatepickerTable(props, context, data) {
  return h(BDatepickerTable, {
    modelValue: data.modelValue.value,
    'onUpdate:modelValue': val => {
      data.modelValue.value = val;
    },
    focusedDate: data.focusedDate.value,
    'onUpdate:focusedDate': val => {
      data.focusedDate.value = val;
    },
    dayNames: props.dayNames,
    monthNames: props.monthNames,
    firstDayOfWeek: props.firstDayOfWeek,
    minDate: props.minDate,
    maxDate: props.maxDate,
    month: data.month.value,
    year: data.year.value,
    isDisabled: data.isDisabled,
    unselectableDates: props.unselectableDates,
    unselectableDaysOfWeek: props.unselectableDaysOfWeek,
    selectableDates: props.selectableDates,
    events: props.events,
    indicators: props.indicators,
    showWeekNumber: props.showWeekNumber
  });
}

function generateFooter(context) {
  return h('footer', {
    class: 'datepicker-footer'
  }, context.slots.footer && context.slots.footer());
}

function generateCalendar(props, context, data) {
  return h('section', {
    class: 'datepicker-content',
    'aria-label': 'Datepicker calendar'
  }, [generateDatepickerTable(props, context, data)]);
}

function generateDatepickerBody(props, context, data) {
  const nodes = [generateHeader(props, context, data), generateCalendar(props, context, data)];

  if (context.slots.footer) {
    nodes.push(generateFooter(context));
  }

  return h('div', nodes);
}

function generateDropdown(props, context, data, dropdown) {
  return h(BDropdown, {
    ref: dropdown,
    position: props.position,
    isDisabled: props.isDisabled,
    isInline: props.isInline
  }, {
    trigger: () => {
      return generateInput(props, context, data);
    },
    default: () => generateDatepickerBody(props, context, data)
  });
}

function getMonths(props, focusedMonth) {
  return props.monthNames.map((month, index) => ({
    value: index,
    text: month,
    isDisabled: false,
    isSelected: focusedMonth === index
  }));
}

function getYears(props, focusedYear) {
  const currentYear = new Date().getFullYear();
  return range(props.yearsRange[0], props.yearsRange[1]).map(inc => currentYear + inc).map(year => ({
    value: year,
    text: year.toString(),
    isDisabled: false,
    isSelected: focusedYear === year
  }));
}

function getSetPreviousMonth(props, month, year) {
  return e => {
    if (e) {
      e.preventDefault();
    }

    if (!props.isDisabled) {
      if (month.value > 0) {
        month.value = month.value - 1;
      } else {
        month.value = 11;
        year.value = year.value - 1;
      }
    }
  };
}

function getSetNextMonth(props, month, year) {
  return e => {
    if (e) {
      e.preventDefault();
    }

    if (!props.isDisabled) {
      const mv = month.value;

      if (mv < 11) {
        month.value = mv + 1;
      } else {
        month.value = 0;
        year.value = year.value + 1;
      }
    }
  };
}

function getSetMonth(monthRef) {
  return month => {
    if (isString(month)) {
      const newVal = fromNullable(parseInt(month, 10));

      if (isSome(newVal)) {
        monthRef.value = newVal.value;
      }
    } else {
      monthRef.value = month;
    }
  };
}

function getSetYear(yearRef) {
  return year => {
    if (isString(year)) {
      const newVal = fromNullable(parseInt(year, 10));

      if (isSome(newVal)) {
        yearRef.value = newVal.value;
      }
    } else {
      yearRef.value = year;
    }
  };
}

const toggleSerialDate = toggleListItem(eqSerialDate);
export default defineComponent({
  name: 'b-datepicker',
  props: BDatepickerPropsDefinition,

  setup(props, context) {
    const fieldData = useFieldData();
    const isDisabled = useDisable(props);
    const dropdown = shallowRef(null);
    const internalValue = shallowRef(props.modelValue);
    watch(() => props.modelValue, newVal => {
      internalValue.value = newVal;
    });
    const modelValue = computed({
      get() {
        return internalValue.value;
      },

      set(val) {
        if (!val) {
          return;
        }

        if (Array.isArray(val) && props.isMultiple || isDate(val)) {
          props['onUpdate:modelValue'](val);
          internalValue.value = val;
        } else if (props.isMultiple && isDate(val)) {
          const newVal = toggleSerialDate(val, internalValue.value == undefined ? [] : Array.isArray(internalValue.value) ? internalValue.value : [internalValue.value]);
          props['onUpdate:modelValue'](newVal);
          internalValue.value = newVal;
        } else if (Array.isArray(val) && isNonEmpty(val)) {
          props['onUpdate:modelValue'](val[0]);
          internalValue.value = val[0];
        }

        if (props.closeOnSelect) {
          dropdown.value && dropdown.value.toggle.setOff();
        }
      }

    });
    const focusedDate = useEqRef(getEq(eqSerialDate))(pipe(fromNullable(props.modelValue), chain(v => Array.isArray(v) ? head(v) : some(v)), alt(() => some(new Date()))));
    const {
      value: month
    } = useProxy(toRef(props, 'month'), toRef(props, 'onUpdate:month'));
    const {
      value: year
    } = useProxy(toRef(props, 'year'), toRef(props, 'onUpdate:year'));
    const nextMonth = getSetNextMonth(props, month, year);
    const previousMonth = getSetPreviousMonth(props, month, year);
    const setMonth = getSetMonth(month);
    const setYear = getSetYear(year);

    function onKeydown(e) {
      if (dropdown.value === undefined || dropdown.value?.$el === undefined || !dropdown.value.$el.contains(e.target)) {
        return;
      }

      if (isEscEvent(e)) {
        dropdown.value && dropdown.value.toggle.setOff();
        return;
      }

      const fd = pipe(focusedDate.value, alt(() => pipe(fromNullable(modelValue.value), chain(v => Array.isArray(v) ? head(v) : some(v)))));

      if (isNone(fd)) {
        return;
      }

      if (isEnterEvent(e) || isSpaceEvent(e)) {
        e.preventDefault();
        modelValue.value = fd.value;
      } else if (isArrowUpEvent(e)) {
        e.preventDefault();
        focusedDate.value = some(addDays(fd.value, -7));
      } else if (isArrowRightEvent(e)) {
        e.preventDefault();
        focusedDate.value = some(addDays(fd.value, 1));
      } else if (isArrowDownEvent(e)) {
        e.preventDefault();
        focusedDate.value = some(addDays(fd.value, 7));
      } else if (isArrowLeftEvent(e)) {
        e.preventDefault();
        focusedDate.value = some(addDays(fd.value, -1));
      }
    }

    onMounted(() => {
      if (typeof window !== 'undefined') {
        document.addEventListener('keyup', onKeydown);
      }
    });
    onUnmounted(() => {
      if (typeof window !== 'undefined') {
        document.removeEventListener('keyup', onKeydown);
      }
    });
    watch(focusedDate, fd => {
      const m = month.value;
      const y = year.value;

      if (isSome(fd)) {
        const fdValue = fd.value;
        const nMonth = fdValue.getMonth();

        if (nMonth !== m) {
          month.value = nMonth;
        }

        const nYear = fdValue.getFullYear();

        if (nYear !== y) {
          year.value = nYear;
        }
      }
    }, {
      immediate: true
    });
    return () => {
      const data = {
        modelValue,
        month,
        year,
        isDisabled: isDisabled.value,
        focusedDate: focusedDate,
        nextMonth,
        previousMonth,
        setMonth,
        setYear,
        months: getMonths(props, month.value),
        years: getYears(props, year.value)
      };
      return h('article', {
        class: ['b-datepicker control', props.size, {
          'is-expanded': props.isExpanded || fieldData.attrs.isExpanded.value
        }]
      }, [useNative(props) ? generateInput(props, context, data) : generateDropdown(props, context, data, dropdown)]);
    };
  }

});
//# sourceMappingURL=BDatepicker.js.map