<template>
  <div ref="paymentStepRef" :class="props.globalClass" :style="cssVars">
    <div v-if="paymentError" class="am-fs__payments-error">
      <AmAlert type="error" :title="paymentError" :show-icon="true" :closable="false"> </AmAlert>
    </div>
    <div v-show="ready && !loading" class="am-fs__payments">
      <div class="am-fs__payments-heading">
        <span class="am-fs__payments-heading-main">
          {{ amLabels.summary }}
        </span>
      </div>

      <div class="am-fs__payments-price">
        <component
          :is="componentTypes[formType]"
          @set-on-site-payment="setOnSitePayment"
        ></component>
      </div>

      <AmCheckbox
        v-if="hasDeposit && fullAmount && paymentGateway !== 'onSite'"
        v-model="paymentDeposit"
        class="am-fs__payments-full"
        :label="amLabels.full_amount_consent"
        :class="{ 'am-fs__payments-full-checked': paymentDeposit }"
        @keydown.enter="paymentDeposit = !paymentDeposit"
      >
      </AmCheckbox>

      <p
        v-show="Object.keys(availablePayments).filter((item) => availablePayments[item]).length > 1"
        class="am-fs__payments-method"
      >
        {{ amLabels.payment_method }}
      </p>
      <div class="am-fs__payments-main">
        <div class="am-fs__payments-main-cards">
          <template v-for="(available, gateway) in availablePayments">
            <div
              v-if="
                available &&
                Object.keys(availablePayments).filter((item) => availablePayments[item]).length > 1
              "
              :key="gateway"
              :class="
                'am-fs__payments-main-button' +
                (paymentGateway === gateway ? ' am-fs__payments-main-button_selected' : '') +
                ' am-fs__payments-main-button-' +
                gateway
              "
              tabindex="0"
              @click="setPaymentGateway(gateway)"
              @keydown.enter="setPaymentGateway(gateway)"
            >
              <img
                v-if="available"
                :src="
                  baseUrls.wpAmeliaPluginURL +
                  '/v3/src/assets/img/icons/' +
                  paymentsBtn.find((item) => item.key === gateway).value.name
                "
                :alt="gateway"
              />
              <div>
                <p>{{ paymentsBtn.find((item) => item.key === gateway).value.text }}</p>
              </div>
            </div>
          </template>
        </div>
      </div>
      <div class="am-fs__payments-sentence">
        <p>{{ getPaymentSentence() }}</p>
      </div>
      <PaymentOnSite
        ref="refOnSitePayment"
        :instant-booking="true"
        :show-recaptcha="false"
        @payment-error="callPaymentError"
      />
      <div v-if="paymentGateway" class="am-fs__payments-pm">
        <component
          :is="paymentTypes[paymentGateway]"
          @payment-error="callPaymentError"
          @payment-abandoned="callPaymentAbandoned"
        />
      </div>
    </div>

    <BookingSkeleton />
  </div>
</template>

<script setup>
import { useStore } from 'vuex'
import { ref, inject, provide, markRaw, watch, computed, onMounted, reactive } from 'vue'
import AmCheckbox from '../../../_components/checkbox/AmCheckbox.vue'
import AmAlert from '../../../_components/alert/AmAlert.vue'
import AppointmentInfo from './parts/AppointmentInfo'
import CartInfo from './parts/CartInfo'
import PaymentStripe from '../../Parts/Payment/PaymentStripe.vue'
import PaymentPayPal from '../../Parts/Payment/PaymentPayPal.vue'
import PaymentOnSite from '../../Parts/Payment/PaymentOnSite.vue'
import PaymentWc from '../../Parts/Payment/PaymentWc.vue'
import PaymentCommon from '../../Parts/Payment/PaymentCommon.vue'
import PaymentSquare from '../../Parts/Payment/PaymentSquare.vue'
import BookingSkeleton from '../../Parts/BookingSkeleton.vue'
import PackageInfo from './parts/PackageInfo'
import { settings } from '../../../../plugins/settings'
import { useColorTransparency } from '../../../../assets/js/common/colorManipulation'
import { usePrepaidPrice, usePaymentError } from '../../../../assets/js/common/appointments'
import useAction from '../../../../assets/js/public/actions'
import { useCart, useCartItem, useCartHasItems } from '../../../../assets/js/public/cart'

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

// * Store
const store = useStore()
const baseUrls = inject('baseUrls')

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

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

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

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

  if (settings.customizedData?.sbsNew?.paymentStep?.translations) {
    let customizedLabels = settings.customizedData.sbsNew.paymentStep.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
})

provide('amLabels', amLabels)

// * Payment Part
const componentTypes = {
  appointment: markRaw(AppointmentInfo),
  package: markRaw(PackageInfo),
  cart: markRaw(CartInfo),
}

let paymentError = computed(() => store.getters['booking/getError'])

// * Step Functions
const { footerBtnDisabledUpdater, headerButtonPreviousClicked, footerButtonClick } = inject(
  'changingStepsFunctions',
  {
    footerBtnDisabledUpdater: () => {},
    headerButtonPreviousClicked: {
      value: false,
    },
    footerButtonClick: () => {},
  },
)

watch(headerButtonPreviousClicked, () => {
  store.commit('booking/setPaymentGateway', '')
})

let cart = computed(() => useCart(store))

const paymentTypes = {
  onSite: markRaw(PaymentOnSite),
  stripe: markRaw(PaymentStripe),
  payPal: markRaw(PaymentPayPal),
  razorpay: markRaw(PaymentCommon),
  mollie: markRaw(PaymentCommon),
  wc: markRaw(PaymentWc),
  square: markRaw(PaymentSquare),
  barion: markRaw(PaymentCommon),
}

let ready = computed(() => store.getters['entities/getReady'])

let loading = computed(() => store.getters['booking/getLoading'])

let formType = computed(() =>
  cart.value.length > 1 ? 'cart' : store.getters['booking/getBookableType'],
)

let paymentGateway = computed(() => {
  if (!store.getters['booking/getPaymentGateway']) {
    store.commit('booking/setPaymentGateway', settings.defaultPaymentMethod)
  }
  return store.getters['booking/getPaymentGateway']
})

let hasDeposit = computed(() => {
  switch (store.getters['booking/getBookableType']) {
    case 'appointment': {
      let depositPayment = false

      useCart(store)
        .filter((i) => 'services' in i && Object.keys(i.services).length)
        .forEach((item) => {
          let service = store.getters['entities/getCategories']
            .find((i) => i.serviceList.filter((j) => j.id === item.serviceId).length)
            .serviceList.find((i) => i.id === item.serviceId)

          if (service.depositPayment !== 'disabled') {
            depositPayment = true
          }
        })

      return ready.value ? depositPayment : false
    }

    case 'package': {
      let item = useCartItem(store)

      let pack = store.getters['entities/getPackage'](item.packageId)

      return ready.value ? pack.depositPayment !== 'disabled' : false
    }
  }

  return false
})

provide('hasDeposit', hasDeposit)

let fullAmount = computed(() => {
  switch (store.getters['booking/getBookableType']) {
    case 'appointment': {
      let fullAmountPayment = false

      useCart(store)
        .filter((i) => 'services' in i && Object.keys(i.services).length)
        .forEach((item) => {
          let service = store.getters['entities/getCategories']
            .find((i) => i.serviceList.filter((j) => j.id === item.serviceId).length)
            .serviceList.find((i) => i.id === item.serviceId)

          if (service.fullPayment) {
            fullAmountPayment = true
          }
        })

      return ready.value ? fullAmountPayment : false
    }

    case 'package': {
      let item = useCartItem(store)

      let pack = store.getters['entities/getPackage'](item.packageId)

      return ready.value ? pack.fullPayment : false
    }
  }

  return false
})

// true = pay full amount
let paymentDeposit = computed({
  get: () => store.getters['booking/getPaymentDeposit'],
  set: (value) => store.commit('booking/setPaymentDeposit', value),
})

let paymentStepRef = ref(null)
provide('paymentStepRef', paymentStepRef)

let mandatoryOnSitePayment = ref(false)

let refOnSitePayment = ref(null)

function callPaymentError(msg) {
  if (store.getters['payment/getOnSitePayment']) {
    store.commit('payment/setOnSitePayment', false)
    store.commit('booking/setPaymentGateway', 'onSite')
    mandatoryOnSitePayment.value = true
    refOnSitePayment.value.continueWithBooking()
  }
  usePaymentError(store, msg)

  if (paymentStepRef.value) {
    paymentStepRef.value.focus()
  }
}

function callPaymentAbandoned() {
  store.commit('booking/setLoading', false)
}

let availablePayments = computed(() => {
  if (ready.value) {
    if (mandatoryOnSitePayment.value) {
      return {
        onSite: true,
        stripe: false,
        payPal: false,
        wc: false,
        mollie: false,
        square: false,
        razorpay: false,
        barion: false,
      }
    }

    let entity = null

    switch (store.getters['booking/getBookableType']) {
      case 'appointment':
        entity =
          useCartHasItems(store) === 1
            ? store.getters['entities/getBookableFromBookableEntities'](
                store.getters['booking/getSelection'],
              )
            : null

        break

      case 'package':
        entity = store.getters['entities/getPackage'](store.getters['booking/getPackageId'])

        break
    }

    let entityPayments = entity && entity.settings ? JSON.parse(entity.settings)['payments'] : null

    let payments = !entityPayments
      ? {
          onSite: settings.payments.onSite,
          stripe: settings.payments.stripe.enabled,
          payPal: settings.payments.payPal.enabled,
          wc: settings.payments.wc.enabled,
          mollie: settings.payments.mollie.enabled,
          square: settings.payments.square.enabled,
          razorpay: settings.payments.razorpay.enabled,
          barion: settings.payments.barion.enabled,
        }
      : {
          onSite:
            'onSite' in entityPayments
              ? entityPayments.onSite && settings.payments.onSite
              : settings.payments.onSite,
          stripe:
            'stripe' in entityPayments
              ? entityPayments.stripe.enabled && settings.payments.stripe.enabled
              : settings.payments.stripe.enabled,
          payPal:
            'payPal' in entityPayments
              ? entityPayments.payPal.enabled && settings.payments.payPal.enabled
              : settings.payments.payPal.enabled,
          wc:
            'wc' in entityPayments
              ? (!('enabled' in entityPayments.wc) || entityPayments.wc.enabled) &&
                settings.payments.wc.enabled
              : settings.payments.wc.enabled,
          mollie:
            'mollie' in entityPayments
              ? entityPayments.mollie.enabled && settings.payments.mollie.enabled
              : settings.payments.mollie.enabled,
          razorpay:
            'razorpay' in entityPayments
              ? entityPayments.razorpay.enabled && settings.payments.razorpay.enabled
              : settings.payments.razorpay.enabled,
          square:
            'square' in entityPayments
              ? entityPayments.square.enabled && settings.payments.square.enabled
              : settings.payments.square.enabled,
          barion:
            'barion' in entityPayments
              ? entityPayments.barion.enabled &&
                settings.payments.barion.enabled &&
                ['USD', 'EUR', 'HUF', 'CZK'].includes(settings.payments.currencyCode)
              : settings.payments.barion.enabled &&
                ['USD', 'EUR', 'HUF', 'CZK'].includes(settings.payments.currencyCode),
        }

    if (
      !payments.onSite &&
      !payments.stripe &&
      !payments.payPal &&
      !payments.wc &&
      !payments.mollie &&
      !payments.square &&
      !payments.razorpay &&
      !payments.barion
    ) {
      payments = {
        onSite: settings.payments.onSite,
        stripe: settings.payments.stripe.enabled,
        payPal: settings.payments.payPal.enabled,
        wc: settings.payments.wc.enabled,
        mollie: settings.payments.mollie.enabled,
        square: settings.payments.square.enabled,
        razorpay: settings.payments.razorpay.enabled,
        barion: settings.payments.barion.enabled,
      }
    }

    if (
      settings.payments.defaultPaymentMethod &&
      payments[settings.payments.defaultPaymentMethod]
    ) {
      store.commit('booking/setPaymentGateway', settings.payments.defaultPaymentMethod)

      footerBtnDisabledUpdater(false)
    } else {
      if (Object.keys(payments).filter((item) => payments[item]).length === 1) {
        for (let key in payments) {
          if (payments[key]) {
            store.commit('booking/setPaymentGateway', key)

            footerBtnDisabledUpdater(false)
          }
        }
      }
    }

    return payments
  }

  return {}
})

function setPaymentGateway(gateway) {
  store.commit('booking/setPaymentGateway', gateway)

  footerBtnDisabledUpdater(false)
}

function setOnSitePayment(isMandatory) {
  if (settings.payments.wc.enabled ? settings.payments.wc.onSiteIfFree : true) {
    if (isMandatory) {
      store.commit('booking/setPaymentGateway', 'onSite')
    }

    mandatoryOnSitePayment.value = isMandatory
  }
}

onMounted(() => {
  if (paymentStepRef.value) {
    paymentStepRef.value.focus()
  }

  const isPaymentStatusError =
    paymentError.value &&
    (paymentError.value === globalLabels.payment_canceled ||
      paymentError.value === globalLabels.payment_error ||
      paymentError.value === globalLabels.payment_error_default)

  // If it's a payment status error (canceled/failed) delay clear for 3s
  if (!isPaymentStatusError) {
    usePaymentError(store, '')
  } else {
    setTimeout(() => {
      usePaymentError(store, '')
    }, 3000)
  }

  if (usePrepaidPrice(store) === 0) {
    if (settings.payments.wc.enabled === true && !settings.payments.wc.onSiteIfFree) {
      store.commit('booking/setPaymentGateway', 'wc')
    } else {
      store.commit('booking/setPaymentGateway', 'onSite')
    }

    footerButtonClick()
  }

  useAction(store, {}, 'InitiateCheckout', formType.value, null, null)
})

let amColors = inject('amColors')

const cssVars = computed(() => {
  return {
    '--am-c-ps-price-bgr': useColorTransparency(amColors.value.colorBtnPrim, 0.05),
    '--am-c-ps-total-price': amColors.value.colorBtnPrim,
    '--am-c-ps-text-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
    '--am-c-ps-text-op50': useColorTransparency(amColors.value.colorMainText, 0.5),
    '--am-c-ps-text-op25': useColorTransparency(amColors.value.colorMainText, 0.25),
    '--am-c-ps-text-op20': useColorTransparency(amColors.value.colorMainText, 0.2),
    '--am-c-ps-text-op06': useColorTransparency(amColors.value.colorMainText, 0.06),
    '--am-c-ps-primary': amColors.value.colorPrimary,
    '--am-c-ps-primary-op10': useColorTransparency(amColors.value.colorPrimary, 0.1),
    '--am-c-ps-primary-op06': useColorTransparency(amColors.value.colorPrimary, 0.06),
  }
})

let paymentsBtn = []

Object.keys(availablePayments.value).forEach((key) => {
  paymentsBtn.push({ key, value: getPaymentBtn(key) })
})

function getPaymentBtn(key) {
  switch (key) {
    case 'onSite':
      return { text: amLabels.value['on_site'], name: 'onSite.svg' }
    case 'payPal':
      return { text: amLabels.value['pay_pal'], name: 'payPal.svg' }
    case 'stripe':
      return { text: amLabels.value['stripe'], name: 'stripe.svg' }
    case 'razorpay':
      return { text: amLabels.value['razorpay'], name: 'razorpay.svg' }
    case 'mollie':
      return { text: amLabels.value['mollie'], name: 'mollie.svg' }
    case 'wc':
      return { text: amLabels.value['on_line'], name: 'online.svg' }
    case 'square':
      return { text: amLabels.value['square'], name: 'square.svg' }
    case 'barion':
      return { text: amLabels.value['barion'], name: 'barion.svg' }
    default:
      return ''
  }
}

function getPaymentSentence() {
  return paymentGateway.value === 'onSite' && !mandatoryOnSitePayment.value
    ? amLabels.value.payment_onsite_sentence
    : paymentGateway.value === 'mollie' ||
        paymentGateway.value === 'wc' ||
        paymentGateway.value === 'barion'
      ? amLabels.value.payment_wc_mollie_sentence
      : ''
}
</script>

<script>
export default {
  name: 'PaymentStep',
  key: 'paymentStep',
  sidebarData: {
    label: 'payment_step',
    icon: 'payment',
    stepSelectedData: [],
    finished: false,
    selected: false,
  },
}
</script>

<style lang="scss">
.amelia-v2-booking #amelia-container {
  .am-fs__main-content.am-fs__payments {
    padding-top: 0;
  }

  .am-fs__payments {
    --am-c-ps-text: var(--am-c-main-text);
    --am-c-ps-border: var(--am-c-inp-border);
    & > * {
      $count: 6;
      @for $i from 0 through $count {
        &:nth-child(#{$i + 1}) {
          animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{$i * 100}ms am-animation-slide-up;
          animation-fill-mode: both;
        }
      }
    }

    &-heading {
      font-size: 15px;
      font-style: normal;
      font-weight: 500;
      line-height: 1.6;
      color: var(--am-c-ps-text);
      margin-bottom: 4px;
      animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
      animation-fill-mode: both;
    }

    &-price {
      border: 1px solid var(--am-c-ps-text-op20);
      border-radius: 8px;
      padding: 16px;
      margin-bottom: 16px;
    }

    &-sentence {
      display: flex;
      justify-content: center;
      margin-top: 2px;
      p {
        display: inline-flex;
        font-size: 14px;
        font-weight: 500;
        line-height: 1.42857;
        color: var(--am-c-ps-text-op60);
      }
    }

    &-full {
      color: var(--am-c-ps-text);
      border: 1px solid var(--am-c-ps-text-op25);
      border-radius: 8px;
      box-shadow: 0 1px 1px var(--am-c-ps-text-op06);
      box-sizing: border-box;
      padding: 12px;
      margin-bottom: 16px;

      &-checked {
        border: 1px solid var(--am-c-ps-primary);
        background: var(--am-c-ps-primary-op10);

        &:after {
          transform: rotate(45deg) scaleY(1);
        }
      }

      .el-checkbox {
        &__input {
          height: 32px;
          line-height: 32px;
          align-items: center;
        }

        &__label {
          line-height: 32px;
          align-items: center;
        }
      }
    }

    &-method {
      font-size: 18px;
      font-weight: 500;
      line-height: 1.55555;
      color: var(--am-c-ps-text);
      margin-bottom: 8px;
    }

    &-error {
      animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
      animation-fill-mode: both;
      margin-bottom: 10px;
    }

    &-main {
      &-cards {
        display: flex;
        gap: 6px;
        justify-items: center;
        flex-wrap: wrap;
      }

      &-button {
        display: flex;
        align-items: center;
        gap: 2px;
        min-width: 108px;
        border: 1px solid var(--am-c-ps-text-op25);
        border-radius: 8px;
        box-shadow: 0 1px 1px var(--am-c-ps-text-op06);
        box-sizing: border-box;
        padding: 12px;
        cursor: pointer;
        flex-direction: column;
        justify-items: center;
        height: fit-content;

        &:focus {
          border: 1px solid var(--am-c-ps-primary);
          box-shadow: 0 1px 1px var(--am-c-ps-primary-op06);
        }

        img {
          height: 24px;
          width: 24px;
        }

        &-barion {
          img {
            height: 24px;
            width: 50px;
          }
        }

        div {
          p {
            font-weight: 500;
            font-size: 15px;
            line-height: 24px;
            color: var(--am-c-ps-text);
            margin: 0;
            text-align: center;
            word-break: break-all;
          }
          span {
            font-size: 12px;
            font-weight: 400;
            line-height: 1.66666;
            color: var(--am-c-ps-text-op50);
          }
        }

        &_selected {
          background: var(--am-c-ps-primary-op10);
          border: 1px solid var(--am-c-ps-primary);
          box-sizing: border-box;
          box-shadow: 0 1px 1px var(--am-c-ps-primary-op06);
        }
      }
    }
    // pm - payment method
    &-pm {
      margin-top: 24px;
    }

    .el-checkbox__label {
      font-size: 15px;
    }
  }
}
</style>
