<template>
  <transition name="toast-fade">
    <view
      class="k-toast"
      v-if="isShow"
      :style="{ cursor: forbidClick ? 'not-allowed' : '' }"
      @click="onClick"
    >
      <view
        class="k-toast-wrapper"
        :class="{
          'k-toast-rectangle': isRectangle,
          'k-toast-dark': mode === 'dark',
          'k-toast-light': mode === 'light',
          'k-toast-row': !isRectangle,
        }"
      >
        <view
          class="k-toast-loading"
          v-show="type === 'loading'"
          :class="{
            'k-toast-loading-large': loadingSize === 'large',
            'k-toast-loading-middle': loadingSize === 'middle',
            'k-toast-loading-small': loadingSize === 'small',
          }"
        >
          <view class="k-toast-after"></view>
        </view>
        <image
          class="k-toast-type-image"
          v-show="type === 'success'"
          src="./images/toast-success.svg"
          alt="success"
        />
        <image
          class="k-toast-type-image"
          v-show="type === 'fail'"
          src="./images/toast-fail.svg"
          alt="fail"
        />
        <image
          class="k-toast-type-image"
          v-show="type === 'info'"
          src="./images/toast-info.svg"
          alt="info"
        />
        <k-icon
          v-show="icon && type === 'text'"
          :name="icon"
          :size="iconSize"
          :color="iconColor"
        ></k-icon>
        <span
          class="k-toast-tip"
          :class="{
            'k-toast-tip-middle': type === 'loading' && loadingSize !== 'large',
          }"
          v-html="text"
        ></span>
      </view>
    </view>
  </transition>
</template>

<script lang="ts">
import Vue from 'vue';
import type { ToastOption } from './k-toast';
export default Vue.extend({
  name: 'k-toast',
  data() {
    return {
      overTextNum: 14,
      isShow: false,
      title: '',
      duration: 1500,
      type: 'text',
      forbidClick: true,
      icon: '',
      iconSize: 16,
      iconColor: '#fff',
      loadingType: 'dark',
      loadingPosition: 'top',
      loadingSize: 'large',
      toastTimer: {} as NodeJS.Timeout,
      position: '',
      complete() {
        // do something
      },
    };
  },
  computed: {
    mode(): string {
      if (this.type === 'loading') {
        if (this.loadingType === 'dark') {
          return 'dark';
        } else {
          return 'light';
        }
      } else {
        return 'dark';
      }
    },
    isRectangle(): boolean {
      if (this.type === 'text') {
        if (this.icon) {
          return true;
        } else {
          return false;
        }
      } else if (this.type === 'loading') {
        if (this.loadingPosition === 'top') {
          return true;
        } else {
          return false;
        }
      } else {
        return true;
      }
    },
    text(): string {
      if ((this.title as string).length > this.overTextNum) {
        const strArr = (this.title as string).split('');
        const regex = /^[\u4E00-\u9FA5]+$/;
        let count = 0;
        return strArr.reduce((pre: string, item: string, index: number) => {
          if (regex.test(item)) {
            count++;
            pre += item;
          } else {
            count += 0.5;
            pre += item;
          }
          if (count + 1 >= this.overTextNum) {
            count = 0;
            pre += '</br>';
          }
          return pre;
        }, '');
      } else {
        return this.title;
      }
    },
  },
  watch: {
    isShow(val) {
      if (!val) {
        clearTimeout(this.toastTimer);
      }
    },
  },
  methods: {
    resetShow(): void {
      if (this.isShow) {
        this.isShow = false;
      }
    },
    showLoading(option: ToastOption): Vue {
      this.resetShow();
      option.type = 'loading';
      this.setToastOption(option);
      return this;
    },
    hideLoading(): void {
      this.isShow = false;
      this.resetToastOption();
    },
    showToast(option: ToastOption): Vue {
      this.resetShow();
      if (!option.title) {
        throw new Error('title is required');
      }
      this.setToastOption(option);
      if (this.type !== 'loading' && this.duration !== 0) {
        this.toastTimer = setTimeout(() => {
          this.hideToast();
        }, this.duration);
      }
      return this;
    },
    hideToast(): void {
      this.isShow = false;
      this.resetToastOption();
    },
    setToastOption(option: ToastOption) {
      this.title = option.title || '';
      this.duration = option.duration === 0 ? 0 : option.duration || 1500;
      this.forbidClick = option.forbidClick || true;
      this.type = option.type || 'text';
      this.icon = option.icon || '';
      this.iconSize = option.iconSize || 16;
      this.iconColor = option.iconColor || '#fff';
      this.loadingType = option.loadingType || 'dark';
      this.loadingPosition = option.loadingPosition || 'top';
      this.loadingSize = option.loadingSize || 'large';
      this.complete =
        option.complete ||
        function () {
          /* do something */
        };
      this.isShow = true;
    },
    resetToastOption(): void {
      this.title = '';
      this.duration = 1500;
      this.forbidClick = true;
      this.type = 'text';
      this.icon = '';
      this.iconSize = 16;
      this.iconColor = '#fff';
      this.loadingType = 'dark';
      this.loadingPosition = 'top';
      this.loadingSize = 'large';
      this.complete();
    },
    onClick(e: TouchEvent): void {
      this.$emit('click', e);
    },
  },
});
</script>

<style scoped lang="scss">
.k-toast {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 100;
  display: flex;
  justify-content: center;
  align-items: center;
  min-width: 100vw;
  height: 100%;

  .k-toast-wrapper {
    padding: 18rpx 28rpx;
    justify-content: center;
    align-items: center;
    border-radius: 8rpx;
    max-width: 60%;
    box-sizing: border-box;
    display: inline-flex;

    &.k-toast-rectangle {
      padding: 30rpx 34rpx 34rpx 24rpx;
      display: flex;
      flex-direction: column;
      min-width: 30%;

      .k-toast-tip {
        margin-top: 15rpx;
      }
    }

    &.k-toast-row {
      display: flex;
      flex-direction: row;

      .k-toast-tip {
        margin-left: 15rpx;
      }
    }

    &.k-toast-dark {
      background-color: rgba($color: #000, $alpha: 0.8);
    }

    .k-toast-tip {
      color: #fff;
      font-size: 28rpx;
      line-height: 40rpx;
      font-weight: 400;
      text-align: center;

      &.k-toast-tip-middle {
        font-size: 24rpx;
        line-height: 34rpx;
      }
    }

    .k-toast-type-image {
      width: 72rpx;
      height: 72rpx;
    }

    .k-toast-loading {
      border: 2px solid #fff;
      border-radius: 50%;
      border-top: 2px solid var(--k-color-primary, #000);
      box-sizing: border-box;
      animation-name: spin;
      animation-duration: 1s;
      animation-iteration-count: infinite;
      animation-timing-function: linear;
      position: relative;

      .k-toast-after {
        box-sizing: border-box;
        border: 1px solid transparent;
        border-radius: 50%;
        border-top: 2px solid #fff;
        position: absolute;
        right: -2px;
        top: -2px;
        display: inline-block;
        transform: rotate(-60deg);
      }

      &.k-toast-loading-large {
        width: 70rpx;
        height: 70rpx;

        .k-toast-after {
          width: 70rpx;
          height: 70rpx;
        }
      }

      &.k-toast-loading-middle {
        width: 56rpx;
        height: 56rpx;

        .k-toast-after {
          width: 56rpx;
          height: 56rpx;
        }
      }

      &.k-toast-loading-small {
        width: 38rpx;
        height: 38rpx;

        .k-toast-after {
          width: 38rpx;
          height: 38rpx;
        }
      }
    }

    &.k-toast-light {
      .k-toast-tip {
        color: #ccc;
      }

      .k-toast-loading {
        border: 2px solid #ccc;
        border-radius: 50%;
        border-top: 2px solid var(--k-color-primary, #000);
        box-sizing: border-box;
        animation-name: spin;
        animation-duration: 1s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;
        position: relative;

        .k-toast-after {
          box-sizing: border-box;
          border: 1px solid transparent;
          border-radius: 50%;
          border-top: 2px solid #ccc;
          position: absolute;
          right: -2px;
          top: -2px;
          display: inline-block;
          transform: rotate(-60deg);
        }
      }
    }
  }

  .k-toast-tip {
    display: box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 6;
    overflow: hidden;
  }

  @keyframes spin {
    0% {
      transform: rotate(0deg);
    }

    100% {
      transform: rotate(360deg);
    }
  }
}

.toast-fade-enter-active {
  transition-duration: 0.4s;
  transition-timing-function: ease;
}

.toast-fade-leave-active {
  transition-duration: 0.4s;
  transition-timing-function: ease;
}

.toast-fade-enter,
.toast-fade-leave-to {
  opacity: 0;
}
</style>
