<template>
  <div class="switch-container" :style="containerStyle">
    <span class="active-background" :style="activeBGStyle"></span>
    <div class="buttons" :style="buttonsStyle">
      <span class="button" :style="buttonStyle" :class="{ active: value }" @click="onSwitch(true)">
        <img src="@/assets/img/home/2D.png" v-if="!text" />
        <span v-else>{{ text[0] }}</span>
      </span>
      <span class="button" :style="buttonStyle" :class="{ active: !value }" @click="onSwitch(false)">
        <img src="@/assets/img/home/3D.png" v-if="!text" />
        <span v-else>{{ text[1] }}</span>
      </span>
    </div>
  </div>
</template>

<script lang="ts">
  import { defineComponent, ref, computed, PropType, watch } from "vue";

  enum TypeEnum {
    vertical = "vertical",
    horizontal = "horizontal",
  }

  export default defineComponent({
    props: {
      /**
       * 展示文字
       */
      text: {
        type: Array,
      },
      /**
       * 值
       */
      value: {
        type: Boolean,
        default: false,
      },
      /**
       * 容器宽度
       */
      width: {
        type: Number,
      },
      /**
       * 容器高度
       */
      height: {
        type: Number,
      },
      /**
       * 水平模式或垂直模式
       */
      type: {
        type: String as PropType<TypeEnum>,
        default: () => TypeEnum.vertical,
      },

      onChange: {
        type: Function,
      },
    },
    setup(props) {
      const width = computed(() => {
        return props.width || (props.type === TypeEnum.vertical ? 30 : 60);
      });

      const height = computed(() => {
        return props.height || (props.type === TypeEnum.vertical ? 60 : 30);
      });

      const containerStyle = computed(() => {
        return {
          width: width.value * 0.01 + "rem",
          height: height.value * 0.01 + "rem",
        };
      });

      const activeBGStyle = computed(() => {
        return {
          left: switchLeft.value * 0.01 + "rem",
          top: switchTop.value * 0.01 + "rem",
          width: (props.type === TypeEnum.vertical ? width.value : width.value / 2) * 0.01 + "rem",
          height: (props.type === TypeEnum.vertical ? height.value / 2 : height.value) * 0.01 + "rem",
        };
      });

      const buttonsStyle = computed(() => {
        return {
          flexDirection: props.type === TypeEnum.vertical ? "column" : "row",
        };
      });

      const buttonStyle = computed(() => {
        return {
          width: (props.type === TypeEnum.vertical ? width.value : width.value / 2) * 0.01 + "rem",
          height: (props.type === TypeEnum.vertical ? height.value / 2 : width.value) * 0.01 + "rem",
          lineHeight: (props.type === TypeEnum.vertical ? height.value / 2 : width.value) * 0.01 + "rem",
        };
      });

      const switchValue = ref<boolean>(props.value),
        switchLeft = ref(props.type === TypeEnum.vertical ? 0 : switchValue.value ? 0 : width.value / 2),
        switchTop = ref(props.type === TypeEnum.horizontal ? 0 : switchValue.value ? 0 : height.value / 2),
        switchTimer = ref<number | null>(null);

      const animation = (e: boolean) => {
        switchTimer.value && cancelAnimationFrame(switchTimer.value);
        const step = 10;
        if (props.type === "horizontal") {
          if (e) {
            switchTimer.value = requestAnimationFrame(left);
          } else {
            switchTimer.value = requestAnimationFrame(right);
          }
        } else {
          if (e) {
            switchTimer.value = requestAnimationFrame(top);
          } else {
            switchTimer.value = requestAnimationFrame(bottom);
          }
        }

        function left() {
          if (switchLeft.value >= step) {
            switchLeft.value -= step;
          } else {
            switchLeft.value = 0;
            switchTimer.value && cancelAnimationFrame(switchTimer.value);
          }
          switchTimer.value = requestAnimationFrame(left);
        }

        function right() {
          if (switchLeft.value <= width.value / 2 - step) {
            switchLeft.value += step;
          } else {
            switchLeft.value = width.value / 2;
            switchTimer.value && cancelAnimationFrame(switchTimer.value);
          }
          switchTimer.value = requestAnimationFrame(right);
        }

        function top() {
          if (switchTop.value >= step) {
            switchTop.value -= step;
          } else {
            switchTop.value = 0;
            switchTimer.value && cancelAnimationFrame(switchTimer.value);
          }
          switchTimer.value = requestAnimationFrame(top);
        }

        function bottom() {
          if (switchTop.value <= height.value / 2 - step) {
            switchTop.value += step;
          } else {
            switchTop.value = height.value / 2;
            switchTimer.value && cancelAnimationFrame(switchTimer.value);
          }
          switchTimer.value = requestAnimationFrame(bottom);
        }
      };

      watch(
        () => props.value,
        (val) => {
          animation(val);
        }
      );

      const onSwitch = (e: boolean) => {
        props.onChange && props.onChange(e);
        animation(e);
      };

      return {
        containerStyle,
        activeBGStyle,
        buttonsStyle,
        buttonStyle,
        switchValue,
        switchLeft,
        switchTop,
        onSwitch,
      };
    },
  });
</script>

<style lang="less" scoped>
  .switch-container {
    position: relative;

    .active-background {
      position: absolute;
      top: 0;
      left: 0;
      display: inline-block;
      background: #5181ff;
      border-radius: 0.08rem;
    }

    .buttons {
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: 10;
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-weight: bold;

      .button {
        text-align: center;
        cursor: pointer;
        font-size: 0.14rem;
        opacity: 0.7;

        img {
          width: 80%;
          height: 80%;
          opacity: 0.7;
        }

        &.active {
          opacity: 1;

          img {
            opacity: 1;
          }
        }

        &:hover {
          opacity: 1;

          img {
            opacity: 1;
          }
        }
      }
    }
  }
</style>
