<!--
 * 动态echar轮播图
  -->
<script setup lang="ts">
import { ref, reactive, onBeforeUnmount, watch, nextTick, markRaw } from 'vue';
import { isEmpty } from 'src/common/utils';
import * as echarts from 'echarts';

interface Props {
  itemKey: string;
  list: any[];
  times?: number;
  navigation?: boolean; // 小圆点点击导航
}

const props = withDefaults(defineProps<Props>(), {
  itemKey: 'id',
  list: () => [],
  times: 10000,
  navigation: false,
});

const DOM_PIE_KEY = 'chart-dom-';

const pointActive = ref<any>(1);
const lastIndex = ref(0);
const timer = ref<any>(null);

const state = reactive({
  // vue3中使用proxy的方式监听响应式，chart会被在vue内部转换成响应式对象，从而在resize 的时候获取不到
  // markRaw 标记一个对象，使其永远不会再成为响应式对象
  domMap: markRaw(new Map()),
});

watch(
  () => props.list,
  () => {
    listChange();
  }
);

onBeforeUnmount(() => {
  offTimer();
});

// list改变
function listChange() {
  // console.log('listChange=', props.list);

  offTimer(); // 清除定时器
  if (isEmpty(props.list)) {
    resetIndex();
    state.domMap.clear();
  } else {
    // 如果当前下标 > list长度，则下标重新开始
    if (pointActive.value > props.list.length) {
      resetIndex();
    }
    nextTick(() => {
      const domMap = new Map();
      props.list.map((item: any) => {
        const id = `${DOM_PIE_KEY}${item[props.itemKey]}`;
        const hasDom = state.domMap.has(id);

        const dom: any = hasDom
          ? state.domMap.get(id).dom
          : document.getElementById(id);
        const option = item.option || null;

        let myChart: any;
        const condition = pointActive.value === item[props.itemKey];
        if (hasDom) {
          if (state.domMap.get(id).myChart) {
            myChart = state.domMap.get(id).myChart;
          } else {
            if (condition) {
              myChart = echarts.init(dom);
            } else {
              myChart = null;
            }
          }
        } else {
          if (condition) {
            myChart = echarts.init(dom);
          } else {
            myChart = null;
          }
        }

        if (condition && option) {
          // console.log('设置了', myChart);
          myChart.clear();
          myChart.setOption(option);
        }
        const val = {
          dom,
          option,
          id,
          myChart,
        };
        if (state.domMap) domMap.set(id, val);
        return val;
      });

      if (state.domMap.size < domMap.size) {
        for (const [key, value] of domMap) {
          if (state.domMap.has(key)) {
            state.domMap.set(key, domMap.get(key));
          } else {
            state.domMap.set(key, value);
          }
        }
      } else if (state.domMap.size > domMap.size) {
        for (const key of state.domMap.keys()) {
          if (domMap.has(key)) {
            state.domMap.set(key, domMap.get(key));
          } else {
            state.domMap.delete(key);
          }
        }
      } else {
        for (const key of domMap.keys()) {
          state.domMap.set(key, domMap.get(key));
        }
      }
      // console.log('state.domMap =', state.domMap);
      onStartTimer();
    });
  }
}

function onStartTimer() {
  timer.value = setTimeout(() => {
    const maxLength = props.list.length;
    if (pointActive.value >= maxLength) {
      pointActive.value = 1;
      lastIndex.value = 0;
    } else {
      pointActive.value++;
      lastIndex.value++;
    }

    nextTick(() => {
      renderChart();
      onStartTimer();
    });
  }, props.times);
}

function onClickPoint(val: any, index: number) {
  if (index === lastIndex.value) return;
  offTimer();
  if (index > lastIndex.value) {
    // 右
  } else if (index < lastIndex.value) {
    // 左
  }
  pointActive.value = val[props.itemKey];
  lastIndex.value = index;

  nextTick(() => {
    renderChart();
    onStartTimer();
  });
}

function renderChart() {
  const key = `${DOM_PIE_KEY}${pointActive.value}`;
  const currentDom = state.domMap.get(key);
  // console.log('currentDom =', currentDom);

  if (currentDom.myChart) {
    if (currentDom.option) {
      currentDom.myChart.clear();
      currentDom.myChart.setOption(currentDom.option);
    }
  } else {
    const myChart = echarts.init(currentDom.dom);
    if (currentDom.option) {
      myChart.clear();
      myChart.setOption(currentDom.option);
    }
    const val = {
      dom: currentDom.dom,
      option: currentDom.option,
      id: currentDom.id,
      myChart,
    };
    state.domMap.set(key, val);
  }
  // console.log('domMap =', state.domMap);
  // console.log('pointActive =', pointActive.value);
}

function offTimer() {
  if (timer.value) {
    clearTimeout(timer.value);
    timer.value = null;
  }
}

function resetIndex() {
  pointActive.value = 1;
  lastIndex.value = 0;
}
</script>
<template>
  <div class="chart-carousel-box">
    <div class="carousel">
      <div class="carousel-content">
        <div class="carousel-item-box">
          <!-- item -->
          <template v-for="(i, index) in props.list" :key="index">
            <div
              class="item-box opacity-in"
              v-show="pointActive === i[props.itemKey]"
            >
              <!-- some item -->
              <div class="my-item-box center">
                <div
                  class="fit"
                  :id="`${DOM_PIE_KEY}${i[props.itemKey]}`"
                ></div>
              </div>
            </div>
          </template>
        </div>
      </div>
      <div class="carousel-points" v-if="props.navigation">
        <div
          class="point"
          :class="{ 'active-point': pointActive === i[props.itemKey] }"
          v-for="(i, index) in props.list"
          :key="index"
          @click="onClickPoint(i, index)"
        ></div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
@keyframes opacity-in {
  0% {
    opacity: 0.5;
    transform: rotateY(180deg);
  }
  100% {
    opacity: 1;
    transform: rotateY(0);
  }
}

.chart-carousel-box {
  width: 100%;
  height: 100%;
}
.carousel {
  width: 100%;
  height: 100%;
  border: 1px solid $primary;
  overflow: hidden;

  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  justify-content: space-between;
}
.carousel-content {
  flex: 1;
  overflow: hidden;
}
.carousel-item-box {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
}
.item-box {
  width: 100%;
  height: 100%;
  overflow: auto;
  position: absolute;
  background-color: #fff;
  top: 0;
  left: 0;
}

.opacity-in {
  animation: opacity-in 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}

.my-item-box {
  width: 100%;
  height: 100%;
  color: #000;
  font-size: 40px;
}

.carousel-points {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  padding: 4px;
  padding-bottom: 0px;
}
.point {
  width: 12px;
  height: 12px;
  margin-right: 4px;
  margin-bottom: 4px;
  border-radius: 50%;
  border: 1px solid $primary;
  cursor: pointer;
  transition: all 0.5s;
}
.active-point {
  height: 10px;
  width: 30px;
  border-radius: 10px;
  background-color: $primary;
}
</style>
