<template>
  <div
    ref="dateTimeRef"
    class="am-fs-dt__calendar"
    :class="[props.globalClass, {'am-oxvisible': (packagesVisibility)}]"
  >
    <div v-if="limitPerEmployeeError" ref="limitError" class="am-fs__payments-error" >
      <AmAlert
        type="error"
        :title="limitPerEmployeeError"
        :show-icon="true"
        :closable="false"
      >
      </AmAlert>
    </div>

    <Calendar
      :id="0"
      :preselect-slot="false"
      :load-counter="loadCounter"
      :end-time="amCustomize.dateTimeStep.options.endTimeVisibility.visibility"
      :time-zone="amCustomize.dateTimeStep.options.timeZoneVisibility.visibility"
      :show-busy-slots="busyTimeSlotsVisibility"
      :show-estimated-pricing="estimatedPricingVisibility"
      :show-indicator-pricing="indicatorPricingVisibility"
      :show-slot-pricing="slotPricingVisibility"
      :show-people-waiting="peopleWaitingVisibility"
      :show-calendar-date-busyness="calendarDateBusynessVisibility"
      :label-slots-selected="amLabels.date_time_slots_selected"
      :label-waiting-list="amLabels.waiting_list"
      :fetched-slots="null"
      :service-id="cartItem ? cartItem.serviceId : 0"
      :date="date"
      :slots-params="slotsParams"
      :tax-visibility="taxVisibility"
      :tax-label="amLabels.total_tax_colon"
      :tax-label-incl="amLabels.incl_tax"
      :is-package="false"
    ></Calendar>

    <!-- Recurring Appointment -->
    <AmSlidePopup
      v-if="service.recurringCycle !== 'disabled' && notLastDay && cart.length <= 1"
      ref="recurringPopupRef"
      :visibility="recurringPopupVisibility"
      class="am-fs-dt__calendar__recurring"
    >
      <div class="am-fs-dt__rec_popup">
        <p>
          {{recurringLabels.repeat_appointment}}
        </p>
        <p v-if="amCustomize.recurringPopup.options.content.visibility">
          {{recurringLabels.repeat_appointment_quest}}
        </p>
      </div>
      <template #footer>
        <AmButton
          category="secondary"
          :type="amCustomize.recurringPopup.options.secondaryButton.buttonType"
          @click="recurringStep(false)"
        >
          {{recurringLabels.no}}
        </AmButton>
        <AmButton
          :type="amCustomize.recurringPopup.options.primaryButton.buttonType"
          @click="recurringStep(true)"
        >
          {{recurringLabels.yes}}
        </AmButton>
      </template>
    </AmSlidePopup>
    <!--/ Recurring Appointment -->

    <!-- Packages Popup -->
    <PackagesPopup @continue-with-service="packagesVisibility = false"></PackagesPopup>
    <!--/ Packages Popup -->

  </div>

</template>

<script setup>
import { useStore } from "vuex";
import {
  ref,
  provide,
  inject,
  computed,
  onMounted,
  watchEffect,
  reactive,
  watch,
  nextTick
} from "vue";
import AmButton from "../../../_components/button/AmButton.vue";
import AmSlidePopup from "../../../_components/slide-popup/AmSlidePopup.vue";
import Calendar from "../../Parts/Calendar.vue";
import {
  useAppointmentParams,
  useRange,
  useSelectedDuration,
  useSelectedDate,
  useSelectedTime,
  useDeselectedDate,
  useSlotsCallback,
} from "../../../../assets/js/public/slots.js"
import { useFormattedPrice } from '../../../../assets/js/common/formatting.js'
import {
  useFillAppointments,
  useDuration,
  usePaymentError,
  useBusySlots,
} from "../../../../assets/js/common/appointments.js";
import {
  useCart,
  useCartItem
} from '../../../../assets/js/public/cart'
import PackagesPopup from "../PakagesStep/parts/PackagesPopup";
import { useCurrentUser } from "../../../../assets/js/public/user";
import { defaultCustomizeSettings } from "../../../../assets/js/common/defaultCustomize";
import AmAlert from "../../../_components/alert/AmAlert.vue";
import { useScrollTo } from "../../../../assets/js/common/scrollElements";
import { useTaxVisibility } from "../../../../assets/js/common/pricing";

let props = defineProps({
  globalClass: {
    type: String,
    default: ''
  },
  showCart: {
    type: Boolean,
    default: false
  }
})

let dateTimeRef = ref(null)
provide('formWrapper', dateTimeRef)

let amCustomize = inject('amCustomize')

// * Busy Time Slots Visibility
let busyTimeSlotsVisibility = computed(() => {
  if ('busyTimeSlotsVisibility' in amCustomize.dateTimeStep.options) {
    return amCustomize.dateTimeStep.options.busyTimeSlotsVisibility.visibility
  }

  return defaultCustomizeSettings.sbsNew.dateTimeStep.options.busyTimeSlotsVisibility.visibility
})

// * Estimated Pricing Visibility
let estimatedPricingVisibility = computed(() => {
  if ('estimatedPricingVisibility' in amCustomize.dateTimeStep.options) {
    return amCustomize.dateTimeStep.options.estimatedPricingVisibility.visibility
  }

  return defaultCustomizeSettings.sbsNew.dateTimeStep.options.estimatedPricingVisibility.visibility
})

// * Indicator Pricing Visibility
let indicatorPricingVisibility = computed(() => {
  if ('indicatorPricingVisibility' in amCustomize.dateTimeStep.options) {
    return amCustomize.dateTimeStep.options.indicatorPricingVisibility.visibility
  }

  return defaultCustomizeSettings.sbsNew.dateTimeStep.options.indicatorPricingVisibility.visibility
})

// * Slot Pricing Visibility
let slotPricingVisibility = computed(() => {
  if ('slotPricingVisibility' in amCustomize.dateTimeStep.options) {
    return amCustomize.dateTimeStep.options.slotPricingVisibility.visibility
  }

  return defaultCustomizeSettings.sbsNew.dateTimeStep.options.slotPricingVisibility.visibility
})

// * Waiting List - Show People Waiting
let peopleWaitingVisibility = computed(() => {
  if ('peopleWaitingVisibility' in amCustomize.dateTimeStep.options) {
    return amCustomize.dateTimeStep.options.peopleWaitingVisibility.visibility
  }

  return defaultCustomizeSettings.sbsNew.dateTimeStep.options.peopleWaitingVisibility.visibility
})

let calendarDateBusynessVisibility = computed(() => {
  if ('calendarDateBusynessVisibility' in amCustomize.dateTimeStep.options) {
    return amCustomize.dateTimeStep.options.calendarDateBusynessVisibility.visibility
  }

  return defaultCustomizeSettings.sbsNew.dateTimeStep.options.calendarDateBusynessVisibility.visibility
})

const store = useStore()

// * Amelia Settings
const amSettings = inject('settings')

// * Labels
const globalLabels = inject('labels')

// * local language short code
const localLanguage = inject('localLanguage')

// * if local lang is in settings lang
let langDetection = computed(() => amSettings.general.usedLanguages.includes(localLanguage.value))

// * Computed labels
let amLabels = computed(() => {
  let computedLabels = reactive({...globalLabels})

  if (amSettings.customizedData?.sbsNew?.dateTimeStep?.translations) {
    let customizedLabels = amSettings.customizedData.sbsNew.dateTimeStep.translations
    Object.keys(customizedLabels).forEach(labelKey => {
      if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
        computedLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
      } else if (customizedLabels[labelKey].default) {
        computedLabels[labelKey] = customizedLabels[labelKey].default
      }
    })
  }
  return computedLabels
})

let recurringLabels = computed(() => {
  let computedLabels = reactive({...globalLabels})

  if (amSettings.customizedData && amSettings.customizedData.sbsNew && amSettings.customizedData.sbsNew.recurringPopup.translations) {
    let customizedLabels = amSettings.customizedData.sbsNew.recurringPopup.translations
    Object.keys(customizedLabels).forEach(labelKey => {
      if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
        computedLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
      } else if (customizedLabels[labelKey].default) {
        computedLabels[labelKey] = customizedLabels[labelKey].default
      }
    })
  }
  return computedLabels
})

let date = computed(() => {
  return cartItem.value &&
      cartItem.value.index !== '' &&
      cartItem.value.services[cartItem.value.serviceId].list.length &&
      cartItem.value.services[cartItem.value.serviceId].list[cartItem.value.index].date
})

let time = computed(() => {
  return cartItem.value &&
    cartItem.value.index !== '' &&
    cartItem.value.services[cartItem.value.serviceId].list.length &&
    cartItem.value.services[cartItem.value.serviceId].list[cartItem.value.index].time
})

let cart = useCart(store)

let cartItem = computed(() => useCartItem(store))

let taxVisibility = computed(() => {
  let visible = amCustomize.dateTimeStep.options.tax?.visibility ?? true
  if (cartItem.value && visible) {
    return useTaxVisibility(store, cartItem.value.serviceId, 'service')
  }
  return false
})

let slotsParams = computed(() => {
  return useAppointmentParams(store)
})

// * Package

let stepIndex = inject('stepIndex')
let shortcodeData = inject('shortcodeData')

let packagesOptions = computed(() => store.getters['entities/filteredPackages'](
    store.getters['booking/getSelection']
))

let packagesVisibility = ref(
  packagesOptions.value.length > 0 &&
  shortcodeData.value.show !== 'services' &&
  stepIndex.value === 0 &&
  cart.length <= 1
)
provide('packagesVisibility', packagesVisibility)

watch(packagesVisibility, (isVisible) => {
  if (!isVisible && dateTimeRef.value) {
    dateTimeRef.value.focus()
  }
})


/**************
 * Navigation *
 *************/

const {
  nextStep,
  footerButtonReset,
  footerBtnDisabledUpdater,
  footerButtonClicked,
  headerButtonPreviousClicked
} = inject('changingStepsFunctions', {
  nextStep: () => {},
  footerButtonReset: () => {},
  footerBtnDisabledUpdater: () => {},
  footerButtonClicked: {
    value: false
  },
  headerButtonPreviousClicked: {
    value: false
  },
})

let limitPerEmployeeError = ref('')
let limitError = ref(null)

watchEffect(() => {
  if (footerButtonClicked.value && date.value && time.value) {
    footerButtonReset()
    limitPerEmployeeError.value = ''

    usePaymentError(store, '')

    if (
      service.recurringCycle !== 'disabled' && service.recurringCycle !== null && notLastDay.value && cart.length <= 1
      && !store.getters['appointmentWaitingListOptions/getIsWaitingListSlot']
    ) {
      recurringPopupVisibility.value = true
    } else {
      let bookingFailed = useFillAppointments(store)

      if (bookingFailed) {
        limitPerEmployeeError.value = amLabels.value.employee_limit_reached
      } else {
        nextStep()
      }
    }
  }
})

watchEffect(() => {
  if (limitPerEmployeeError.value && limitError.value) {
      useScrollTo(dateTimeRef.value, limitError.value, 0, 300)
  }
})

watchEffect(() => {
  footerBtnDisabledUpdater(!date.value || !time.value)
}, { flush: 'post' })


/*****************
 * Calendar Data *
 ****************/

let loadCounter = ref(0)

let calendarChangeSideBar = ref(true)

provide('calendarChangeSideBar', calendarChangeSideBar)

let calendarSlotDuration = ref(0)

provide('calendarSlotDuration', calendarSlotDuration)

let calendarServiceDuration = ref(0)

provide('calendarServiceDuration', calendarServiceDuration)

let calendarServiceDurations = ref([])

provide('calendarServiceDurations', calendarServiceDurations)

provide('useSlotsCallback', useSlotsCallback)

provide('useRange', useRange)

provide('useSelectedDuration', useSelectedDuration)

provide('useBusySlots', useBusySlots)

provide('useSelectedDate', useSelectedDate)

provide('useSelectedTime', useSelectedTime)

provide('useDeselectedDate', useDeselectedDate)


/*********
 * Other *
 ********/

let service = reactive({})

let recurringPopupVisibility = ref(false)
let recurringPopupRef = ref(null)

let { goToRecurringStep } = inject('goToRecurringStep', {
  goToRecurringStep: () => {}
})

let { removeRecurringStep } = inject('removeRecurringStep', {
  removeRecurringStep: () => {}
})

// * Focus management for keyboard navigation on Recurring Appointment Popup
watch(recurringPopupVisibility, async (isVisible) => {
  if (isVisible) {
    // Wait for DOM to update
    await nextTick()
    let footerButton = recurringPopupRef.value?.$el?.querySelector('.am-button--secondary')
    if (footerButton) {
      footerButton.focus()
    }
  }
})

let notLastDay = computed(() => {
  if (cartItem.value &&
      cartItem.value.index !== '' &&
      cartItem.value.services[cartItem.value.serviceId].list.length
  ) {
    let lastDate = store.getters['booking/getMultipleAppointmentsLastDate']
    let chosenDate = store.getters['booking/getMultipleAppointmentsDate']
    return lastDate !== chosenDate
  }
  return false
})

function recurringStep (repeat) {
  if (repeat) {
    goToRecurringStep()
  } else {
    if (cartItem.value &&
      'serviceId' in cartItem.value &&
      cartItem.value.serviceId in cartItem.value.services &&
      cartItem.value.services[cartItem.value.serviceId].list.length > 1
    ) {
      store.commit('booking/unsetRecurringItems')
    }

    limitPerEmployeeError.value = ''
    let bookingFailed = useFillAppointments(store)

    if (bookingFailed) {
      limitPerEmployeeError.value = amLabels.value.employee_limit_reached
    } else {
      nextStep()
    }
  }
}

function setDurationsPrices (service, durations) {
  if (service.customPricing.enabled === 'duration') {
    Object.keys(service.customPricing.durations).forEach((duration) => {
      if (!(duration in durations)) {
        durations[parseInt(duration)] = []
      }

      durations[parseInt(duration)].push(service.customPricing.durations[duration].price)
    })
  }

  return durations
}

function getDurations () {
  let durations = {}

  let serviceId = store.getters['booking/getServiceId']

  let employeeId = store.getters['booking/getEmployeeId']

  if (!employeeId && serviceId) {
    let employees = store.getters['entities/filteredEmployees'](
      store.getters['booking/getSelection']
    )

    employees.forEach((provider) => {
      let service = provider.serviceList.find(service => service.id === serviceId)

      durations = setDurationsPrices(service, durations)
    })
  } else {
    let employee = store.getters['entities/getEmployee'](store.getters['booking/getEmployeeId'])

    let service = employee.serviceList.find(service => service.id === serviceId)

    durations = setDurationsPrices(service, durations)
  }

  let result = []

  Object.keys(durations).sort((a, b) => a - b).forEach((duration) => {
    let min = Math.min(...durations[duration])

    let max = Math.max(...durations[duration])

    result.push(
      {
        duration: parseInt(duration),
        priceLabel: min !== max
          ? useFormattedPrice(min) + ' - ' + useFormattedPrice(max)
          : (min === 0 ? '' : useFormattedPrice(min))
      }
    )
  })

  return result
}

onMounted(() => {
  if (props.showCart && !store.getters['booking/getShownCart']) {
    return
  }

  service = store.getters['entities/getService'](
    cartItem.value.serviceId
  )

  calendarServiceDurations.value = getDurations()

  let serviceDuration = store.getters['booking/getBookingDuration']

  serviceDuration = serviceDuration && calendarServiceDurations.value.filter(i => i.duration === serviceDuration).length
    ? serviceDuration : service.duration

  store.commit('booking/setBookingDuration', serviceDuration)

  let extrasIds = store.getters['booking/getSelectedExtras'].map(i => i.extraId)

  calendarSlotDuration.value = useDuration(serviceDuration, service.extras.filter(i => extrasIds.includes(i.id)))

  calendarServiceDuration.value = serviceDuration

  let index = store.getters['booking/getCartItemIndex']

  let items = store.getters['booking/getAllMultipleAppointments']

  let hasItem = index in items

  if (
    (hasItem && cartItem.value.services[cartItem.value.serviceId].list.length > 1) ||
    store.getters['appointmentWaitingListOptions/getIsWaitingListSlot']
  ) {
    removeRecurringStep()
  }

  useCurrentUser(store, shortcodeData.value.hasApiCall)

  if ('serviceId' in cartItem.value &&
    cartItem.value.serviceId in cartItem.value.services &&
    cartItem.value.index in cartItem.value.services[cartItem.value.serviceId].list
  ) {
    cartItem.value.services[cartItem.value.serviceId].list[cartItem.value.index].providerId = null

    cartItem.value.services[cartItem.value.serviceId].list[cartItem.value.index].locationId = null
  }

  loadCounter.value++

  if (dateTimeRef.value && !packagesVisibility.value) {
    dateTimeRef.value.focus()
  }
})
</script>

<script>
export default {
  name: 'DateTimeStep',
  key: 'dateTimeStep',
  sidebarData: {
    label: 'date_time',
    icon: 'date-time',
    stepSelectedData: [],
    finished: false,
    selected: false,
  }
}
</script>

<style lang="scss">
// am -- amelia
// fs -- form steps

.amelia-v2-booking #amelia-container {
  // Amelia Form Steps
  .am-fs {
    &__main {
      &-content.am-fs-dt__calendar {
        &.am-oxvisible {
          overflow-x: visible;
        }
      }
    }

    // Container Wrapper
    &__main {
      &-heading {
        &-inner {
          display: flex;
          align-items: center;

          .am-heading-prev {
            margin-right: 12px;
          }
        }
      }
      &-inner {
        &#{&}-dt {
          padding: 0 20px;
        }
      }
    }

    &-dt__rec_popup {
      margin: 16px 0 48px 0;
      & > p {
        font-size: 15px;
        line-height: 1.6;
        color: var(--am-c-main-text);

        &:first-child {
          font-weight: 500;
          margin-bottom: 7px;
        }

        &:last-child {
          font-weight: 400;
        }
      }
    }
  }
}
</style>
