<template>
  <div class="card-item relative w-2/4 lg:w-3/4 h-48 m-auto" :class="{ '-active' : isCardFlipped }">
    <div class="card-item__side h-full rounded-lg shadow-lg overflow-hidden" style="transform: perspective(2000px) rotateY(0deg) rotateX(0deg) rotate(0deg);
  transform-style: preserve-3d;
  transition: all 0.8s cubic-bezier(0.71, 0.03, 0.56, 0.85);
  backface-visibility: hidden;">
      <div
        class="absolute w-full h-full left-0 right-0 top-0 rounded-sm overflow-hidden z-10 pointer-events-none opacity-0"
        style="transition: all 0.35s cubic-bezier(0.71, 0.03, 0.56, 0.85);"
        :class="{'opacity-100' : focusElementStyle }"
        :style="focusElementStyle"
        ref="focusElement"
      ></div>
      <div class="absolute w-full h-full bg-black left-0 top-0 rounded-lg overflow-hidden" style="background-image: linear-gradient(147deg, #354fce 0%, #0c296b 74%);">
      </div>
      <div class="relative h-full py-6 px-4 select-none">
        <div class="flex items-start justify-between px-4">
          <img
            :src="chip_src"
            class="w-12"
          />
          <div class="relative w-full h-12 flex flex-end">
            <transition name="slide-fade-up">
              <img
                :src="card_type_src + cardType + '.png'"
                v-if="cardType"
                :key="cardType"
                alt
                class="w-full h-full object-right-top	object-contain"
              />
            </transition>
          </div>
        </div>
        
        <div class="flex items-start justify-between text-white">
          <label :for="fields.cardName" class="p-2 block cursor-pointer text-white" :ref="fields.cardName">
            <transition name="slide-fade-up">
              <div class="text-lg overflow-hidden" v-if="labels.cardName.length" key="1">
                <transition-group name="slide-fade-right">
                  <span
                    class="text-lg overflow-hidden"
                    v-for="(n, $index) in labels.cardName.replace(/\s\s+/g, ' ')"
                    :key="$index + 1"
                  >{{n}}</span>
                </transition-group>
              </div>
              <div class="text-lg overflow-hidden" v-else key="2">Full Name</div>
            </transition>
          </label>
          <div class="flex flex-wrap shrink-0 text-lg p-2 cursor-pointer" ref="cardDate">
            <label :for="fields.cardMonth" class="card-item__dateItem">
              <transition name="slide-fade-up">
                <span v-if="labels.cardMonth" :key="labels.cardMonth">{{labels.cardMonth}}</span>
                <span v-else key="2">MM</span>
              </transition>
            </label>
            /
            <label for="cardYear" class="card-item__dateItem">
              <transition name="slide-fade-up">
                <span v-if="labels.cardYear" :key="labels.cardYear">{{String(labels.cardYear).slice(2,4)}}</span>
                <span v-else key="2">YY</span>
              </transition>
            </label>
          </div>
        </div>

        <label :for="fields.cardNumber" class="flex justify-around font-medium text-white text-lg p-3 cursor-pointer" :ref="fields.cardNumber">
          <template>
            <span v-for="(n, $index) in currentPlaceholder" :key="$index">
              <transition name="slide-fade-up">
                <div class="w-2" v-if="getIsNumberMasked($index, n)">*</div>
                <div
                  class="w-2"
                  :class="{ '-active' : n.trim() === '' }"
                  :key="currentPlaceholder"
                  v-else-if="labels.cardNumber.length > $index"
                >{{labels.cardNumber[$index]}}</div>
                <div
                  class="w-2"
                  :class="{ '-active' : n.trim() === '' }"
                  v-else
                  :key="currentPlaceholder + 1"
                >{{n}}</div>
              </transition>
            </span>
          </template>
        </label>
      </div>
    </div>
    <div class="card-item__side -back absolute top-0 left-0 w-full p-0 h-full">
      <div class="absolute w-full h-full bg-black left-0 top-0 rounded-lg overflow-hidden" style="background-image: linear-gradient(147deg, #354fce 0%, #0c296b 74%);">
      </div>
      <div class="absolute w-full h-32 mt-12 bg-black"></div>
      <div class="relative p-4 text-right">
        <div class="pr-4 text-white mb-3">CVV</div>
        <div class="h-12 flex items-center justify-end text-black rounded-sm shadow-lg bg-white text-right">
          <span v-for="(n, $index) in labels.cardCvv" :key="$index">*</span>
        </div>
        <div class="relative w-24 h-12 flex justify-end">
          <img
            :src="card_type_src + cardType + '.png'"
            v-if="cardType"
            class="w-full h-full object-right-top object-contain"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Card',
  props: {
    labels: Object,
    fields: Object,
    isCardNumberMasked: Boolean,
    randomBackgrounds: {
      type: Boolean,
      default: true
    },
    backgroundImage: [String, Object]
  },
  data () {
    return {
      focusElementStyle: null,
      currentFocus: null,
      isFocused: false,
      isCardFlipped: false,
      amexCardPlaceholder: '#### ###### #####',
      dinersCardPlaceholder: '#### ###### ####',
      defaultCardPlaceholder: '#### #### #### ####',
      currentPlaceholder: '',
      chip_src: app_url + '/public/img/credit_card/chip.png',
      card_type_src: app_url + '/public/img/credit_card/',
    }
  },
  watch: {
    currentFocus () {
      if (this.currentFocus) {
        this.changeFocus()
      } else {
        this.focusElementStyle = null
      }
    },
    cardType () {
      this.changePlaceholder()
    }
  },
  mounted () {
    this.changePlaceholder()

    let self = this
    let fields = document.querySelectorAll('[data-card-field]')
    fields.forEach(element => {
      element.addEventListener('focus', () => {
        this.isFocused = true
        if (element.id === this.fields.cardYear || element.id === this.fields.cardMonth) {
          this.currentFocus = 'cardDate'
        } else {
          this.currentFocus = element.id
        }
        this.isCardFlipped = element.id === this.fields.cardCvv
      })
      element.addEventListener('blur', () => {
        this.isCardFlipped = !element.id === this.fields.cardCvv
        setTimeout(() => {
          if (!self.isFocused) {
            self.currentFocus = null
          }
        }, 300)
        self.isFocused = false
      })
    })
  },
  computed: {
    cardType () {
      let number = this.labels.cardNumber
      let re = new RegExp('^4')
      if (number.match(re) != null) return 'visa'

      re = new RegExp('^(34|37)')
      if (number.match(re) != null) return 'amex'

      re = new RegExp('^5[1-5]')
      if (number.match(re) != null) return 'mastercard'

      re = new RegExp('^6011')
      if (number.match(re) != null) return 'discover'

      re = new RegExp('^62')
      if (number.match(re) != null) return 'unionpay'

      re = new RegExp('^9792')
      if (number.match(re) != null) return 'troy'

      re = new RegExp('^3(?:0([0-5]|9)|[689]\\d?)\\d{0,11}')
      if (number.match(re) != null) return 'dinersclub'

      re = new RegExp('^35(2[89]|[3-8])')
      if (number.match(re) != null) return 'jcb'

      return '' // default type
    },
    currentCardBackground () {
      if (this.randomBackgrounds && !this.backgroundImage) { // TODO will be optimized
        let random = Math.floor(Math.random() * 25 + 1)
        return `https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/${random}.jpeg`
      } else if (this.backgroundImage) {
        return this.backgroundImage
      } else {
        return null
      }
    }
  },
  methods: {
    changeFocus () {
      let target = this.$refs[this.currentFocus]
      this.focusElementStyle = target ? {
        width: `${target.offsetWidth}px`,
        height: `${target.offsetHeight}px`,
        transform: `translateX(${target.offsetLeft}px) translateY(${target.offsetTop}px)`
      } : null
    },
    getIsNumberMasked (index, n) {
      return index > 4 && index < 14 && this.labels.cardNumber.length > index && n.trim() !== '' && this.isCardNumberMasked
    },
    changePlaceholder () {
      if (this.cardType === 'amex') {
        this.currentPlaceholder = this.amexCardPlaceholder
      } else if (this.cardType === 'dinersclub') {
        this.currentPlaceholder = this.dinersCardPlaceholder
      } else {
        this.currentPlaceholder = this.defaultCardPlaceholder
      }
      this.$nextTick(() => {
        this.changeFocus()
      })
    }
  }
}
</script>

<style scoped>
.card-item.-active .card-item__side.-front {
  transform: perspective(1000px) rotateY(180deg) rotateX(0deg) rotateZ(0deg);
}
.card-item.-active .card-item__side.-back {
  transform: perspective(1000px) rotateY(0) rotateX(0deg) rotateZ(0deg);
}

.card-item__side {
  border-radius: 15px;
  overflow: hidden;
  transform: perspective(2000px) rotateY(0deg) rotateX(0deg) rotate(0deg);
  transform-style: preserve-3d;
  transition: all 0.8s cubic-bezier(0.71, 0.03, 0.56, 0.85);
  backface-visibility: hidden;
  height: 100%;
}

.card-item__side.-back {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  transform: perspective(2000px) rotateY(-180deg) rotateX(0deg) rotate(0deg);
  z-index: 2;
  padding: 0;
  height: 100%;
}
</style>