<template>
  <div class="flip-clock">
    <template v-for="data in timeData" v-show="show">
      <span v-bind:key="data.label" class="flip-clock__piece" :id="data.elementId" v-show="data.show">
        <span :class="['flip-clock__card', 'flip-card', clockClasses ]">
          <b class="flip-card__top">{{ data.current | twoDigits }}</b>
          <b class="flip-card__bottom" v-bind:data-value="data.current | twoDigits"></b>
          <b class="flip-card__back" v-bind:data-value="data.previous | twoDigits"></b>
          <b class="flip-card__back-bottom" v-bind:data-value="data.previous | twoDigits"></b>
        </span>
        <span :class="['flip-clock__slot', 'font-alt', slotClasses]">{{ data.label }}</span>
      </span>
    </template>
  </div>
</template>

<script>
import Vue from "vue";
import { forEachNode } from "../utils";

export default {
  name: 'flipCountdown',
  props: {
    deadline: {
      type: String,
    },
    stop: {
      type: Boolean,
    },
    units: {
      type: String,
      default: 'days,hours,minutes,seconds'
    },
    clockClasses: {
      type: String,
      default: 'text-6xl'
    },
    slotClasses: {
      type: String,
      default: 'text-3xl'
    }
  },
  data() {
    const uuid = Math.floor(Math.random() * 100);
    return {
      now: Math.trunc(new Date().getTime() / 1000),
      date: null,
      interval: null,
      diff: 0,
      show: false,
      timeData: [
        {
          current: 0,
          previous: 0,
          label: "Dní",
          elementId: 'flip-card-days-' + uuid,
          show: this.units.indexOf("days") !== -1,
        },
        {
          current: 0,
          previous: 0,
          label: "Hod",
          elementId: 'flip-card-hours-' + uuid,
          show: this.units.indexOf("hours") !== -1,
        },
        {
          current: 0,
          previous: 0,
          label: "Min",
          elementId: 'flip-card-minutes-' + uuid,
          show: this.units.indexOf("minutes") !== -1,
        },
        {
          current: 0,
          previous: 0,
          label: "Sek",
          elementId: 'flip-card-seconds-' + uuid,
          show: this.units.indexOf("seconds") !== -1,
        },
      ],
    };
  },
  created() {
    if (!this.deadline) {
      throw new Error("Missing props 'deadline'");
    }

    const endTime = this.deadline;
    this.date = Math.trunc(Date.parse(endTime.replace(/-/g, '/')) / 1000);

    if (!this.date) {
      throw new Error("Invalid props value, correct the 'deadline'");
    }

    this.interval = setInterval(() => {
      this.now = Math.trunc(new Date().getTime() / 1000);
    }, 1000);
  },
  mounted() {
    if (this.diff !== 0) {
      this.show = true;
    }
  },
  watch: {
    deadline(newVal, oldVal) {
      const endTime = this.deadline;
      this.date = Math.trunc(Date.parse(endTime.replace(/-/g, '/')) / 1000);

      if (!this.date) {
        throw new Error("Invalid props value, correct the 'deadline'");
      }
    },
    now(value) {
      this.diff = this.date - value;

      if (this.diff <= 0 || this.stop) {
        this.diff = 0;
        this.updateTime(3, 0);
      } else {
        this.updateTime(0, Math.trunc(this.diff / 60 / 60 / 24));
        this.updateTime(1, Math.trunc(this.diff / 60 / 60) % 24);
        this.updateTime(2, Math.trunc(this.diff / 60) % 60);
        this.updateTime(3, Math.trunc(this.diff) % 60);
      }
    },
  },
  filters: {
    twoDigits(value) {
      if (value.toString().length <= 1) {
        return '0' + value.toString();
      }
      return value.toString();
    },
  },
  methods: {
    updateTime(idx, newValue) {
      if (idx >= this.timeData.length || newValue === undefined) {
        return;
      }

      const applyUpdate = () => {
        const d = this.timeData[idx];
        const val = newValue < 0 ? 0 : newValue;
        const el = document.querySelector(`#${d.elementId}`);
        if (val !== d.current) {
          d.previous = d.current;
          d.current = val;
          if (el) {
            el.classList.remove('flip');
            void el.offsetWidth;
            el.classList.add('flip');
          }
          if (idx === 0) {
            const els = el.querySelectorAll('span b');
            if (els) {
              forEachNode(els, e => {
                const cls = e.classList[0];
                if (newValue / 1000 >= 1) {
                  if (!cls.includes('-4digits')) {
                    const newCls = cls + '-4digits';
                    e.classList.add(newCls);
                    e.classList.remove(cls);
                  }
                } else {
                  if (cls.includes('-4digits')) {
                    const newCls = cls.replace('-4digits', '');
                    e.classList.add(newCls);
                    e.classList.remove(cls);
                  }
                }
              });
            }
          }
        }
      };

      if (window['requestAnimationFrame']) {
        this.frame = requestAnimationFrame(applyUpdate);
      } else {
        applyUpdate();
      }
    },
  },
  beforeDestroy() {
    if (window['cancelAnimationFrame']) {
      cancelAnimationFrame(this.frame);
    }
  },
  destroyed() {
    clearInterval(interval);
  }
}
</script>
