<template>
  <div
    class="nv-progress"
    :class="{ reversed: reversed, rounded: rounded }"
    :style="{ minHeight: `${height}px` }"
  >
    <div
      class="nv-progress__background"
      :style="{
        background: computedBackgroundColor,
      }"
    >
      <div
        class="nv-progress__buffer"
        :style="{
          width: indeterminate ? 0 : `${bufferWidth * 100}%`,
          background: computedValueColor,
        }"
      ></div>
      <div
        ref="value"
        class="nv-progress__value"
        :style="{
          width: indeterminate ? 0 : `${valueWidth * 100}%`,
          background: computedValueColor,
        }"
      ></div>
    </div>
    <div class="nv-progress__slot"><slot /></div>
  </div>
</template>

<script>
export default {
  name: "NvProgress",

  props: {
    backgroundColor: { type: String, default: "#eeeeee" },
    backgroundColorGradientTo: { type: String, default: undefined },
    buffer: { type: Number, default: 0 },
    color: { type: String, default: "" },
    colorGradientTo: { type: String, default: undefined },
    height: { type: Number, default: 4 },
    indeterminate: Boolean,
    total: { type: Number, default: 100 },
    value: { type: Number, default: 0 },
    speed: { type: Number, default: 600 },
    reversed: Boolean,
    rounded: Boolean,
  },

  data: () => {
    return {};
  },

  computed: {
    computedValueColor() {
      if (!this.color) return;
      return `linear-gradient(${this.reversed ? "-" : ""}90deg, ${
        this.color
      } 0%, ${this.colorGradientTo ?? this.color} ${
        100 / (this.valueWidth || 1)
      }%)`;
    },
    computedBackgroundColor() {
      if (!this.backgroundColor) return;
      return `linear-gradient(${this.reversed ? "-" : ""}90deg, ${
        this.backgroundColor
      } 0%, ${this.backgroundColorGradientTo || this.backgroundColor} 100%)`;
    },

    bufferWidth() {
      return Math.min(1, this.buffer / this.total);
    },
    valueWidth() {
      return Math.min(1, this.value / this.total);
    },
  },
  mounted() {
    if (this.indeterminate) {
      this.$nextTick(() => this.animation());
    }
  },

  methods: {
    animation() {
      const sec = this.speed / 1000;
      const el = this.$refs.value;
      el.style[this.reversed ? "right" : "left"] = 0;
      el.style.width = 0;
      el.style.transition = `right ${sec}s, left ${sec}s, width ${sec}s`;

      setTimeout(() => {
        el.style.width = "100%";
      }, 0);

      setTimeout(() => {
        el.style.width = 0;
        el.style[this.reversed ? "right" : "left"] = "100%";
      }, this.speed);

      setTimeout(() => {
        el.style.transition = "none";
        el.style[this.reversed ? "right" : "left"] = 0;
        setTimeout(this.animation, this.speed);
      }, this.speed * 2);
    },
  },
};
</script>

<style lang="scss" scoped>
.nv-progress {
  @apply w-full relative;

  &__background {
    @apply h-full w-full absolute overflow-hidden top-0 left-0;
  }

  &__buffer {
    @apply bg-primary absolute top-0 left-0 h-full opacity-30;
    transition: width 0.2s;
  }

  &__value {
    @apply bg-primary absolute top-0 left-0 h-full;
    transition: background 0.2s;
  }
  &__slot {
    @apply flex flex-wrap items-center justify-center z-10 text-white relative;
  }

  &.reversed {
    .nv-progress__buffer {
      @apply left-auto right-0;
    }

    .nv-progress__value {
      @apply left-auto right-0;
    }
  }

  &.rounded {
    .nv-progress__background {
      @apply rounded-full;
    }

    .nv-progress__buffer {
      @apply rounded-full;
    }

    .nv-progress__value {
      @apply rounded-full;
    }
  }
}
</style>
