<template>
  <div ref="boxRef" class="w-full mb-5">
    <table
      :border="element.componentProps.borderWidth"
      cellspacing="0"
      :style="{
        borderColor: element.componentProps.borderColor,
        width: tableWidth + 'px',
        tableLayout: 'fixed',
      }"
    >
      <colgroup>
        <col v-for="(tdElement, tdIndex) of tdMax" :key="tdElement" :width="widthArr[tdIndex]" />
      </colgroup>

      <tbody>
        <tr
          v-for="(row, rowIndex) of element.children"
          :key="rowIndex"
          style="background-color: #fff"
        >
          <td
            v-for="(tdElement, tdIndex) of row.list"
            :key="tdIndex"
            :colspan="tdElement.colspan"
            :rowspan="tdElement.rowspan"
            :data-position="tdElement.position"
            :style="{
              borderColor: element.componentProps.borderColor,
              borderWidth: element.componentProps.borderWidth + 'px',
              borderStyle: 'solid',
              position: 'relative',
              verticalAlign: 'top',
            }"
          >
            <slot name="tdElement" :tdElement="tdElement" :key="tableKey"></slot>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script lang="ts" setup>
  import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';

  const props = defineProps({
    element: {
      type: Object,
      required: true,
    },
  });

  const tdMax = ref(0);
  const boxRef = ref();
  const tableKey = ref(0);
  const widthArr = ref<number[]>([]);
  const tableWidth = ref(0);
  const resizeObserver = new ResizeObserver((entries) => {
    const { width } = entries[0].contentRect;
    compulateWidth(width);
  });
  onMounted(() => {
    tdMax.value = 0;
    props.element.children[0].list.forEach((o) => {
      if (o.colspan) {
        tdMax.value = tdMax.value + o.colspan;
      } else {
        tdMax.value += 1;
      }
    });
    compulateWidth();

    if (boxRef.value) resizeObserver.observe(boxRef.value);
    setTimeout(() => {
      tableKey.value++;
    }, 20);
  });
  onBeforeUnmount(() => {
    resizeObserver.unobserve(boxRef.value);
  });
  watch(
    () => props.element.children,
    async (val) => {
      tdMax.value = 0;
      val[0].list.forEach((o) => {
        if (o.colspan) {
          tdMax.value = tdMax.value + o.colspan;
        } else {
          tdMax.value += 1;
        }
      });
      compulateWidth();
    },
    { deep: true },
  );

  function compulateWidth(width?) {
    nextTick(() => {
      let oldWidth = 0;
      let thCount = 0;
      let newwidth = 0;
      let hasWidth = {};

      for (let j = 0; j < tdMax.value; j++) {
        hasWidth[j] = null;
      }
      for (let i = 0; i < props.element.children.length; i++) {
        for (let k = 0; k < props.element.children[i].list.length; k++) {
          let obj = props.element.children[i].list[k];
          if (Object.keys(hasWidth).includes(String(obj.position[1])) && obj.width) {
            hasWidth[obj.position[1]] = obj;
            oldWidth += Number(obj.width);
          }
        }
      }
      for (let i in hasWidth) {
        if (hasWidth[i]) {
          thCount += 1;
        }
      }

      if (tdMax.value - thCount > 0) {
        tableWidth.value = width || boxRef.value?.offsetWidth;
        newwidth = Math.floor(
          (boxRef.value.offsetWidth - oldWidth - tdMax.value * 2) / (tdMax.value - thCount),
        );
      } else {
        tableWidth.value = oldWidth;
      }
      widthArr.value = [];
      for (let i in hasWidth) {
        if (hasWidth[i]) {
          widthArr.value.push(hasWidth[i].width);
        } else {
          widthArr.value.push(newwidth);
        }
      }
    });
  }
</script>
