<template>
  <div ref="boxRef" style="width: 100%">
    <table
      :border="element.options.borderWidth"
      cellspacing="0"
      cellpadding="0"
      :style="{
        borderColor: element.options.borderColor,
        width: tableWidth + 'px',
        tableLayout: 'fixed',
        height: '42px',
      }"
    >
      <thead>
        <tr style="background-color: #f6f8fa">
          <th
            v-for="(tdElement, tdIndex) of tdMax"
            :key="tdElement"
            style="border: 1px solid #eee"
            @click.stop="handleTh(tdIndex)"
          >
            <div
              :style="{
                height: '22px',
                width: widthArr[tdIndex] + 'px' || '',
              }"
            ></div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="(row, rowIndex) of element.layout"
          :key="rowIndex"
          style="background-color: #fff"
        >
          <td
            v-for="(tdElement, tdIndex) of row.list"
            :key="rowIndex + '-' + tdIndex"
            :colspan="tdElement.colspan"
            :rowspan="tdElement.rowspan"
            :data-position="tdElement.position"
            :style="{
              borderColor: element.options.borderColor,
              borderWidth: element.options.borderWidth + 'px',
              borderStyle: 'solid',
              position: 'relative',
              backgroundColor:
                curTdIndex == rowIndex + '-' + tdIndex || curThIndex == tdElement.position[1]
                  ? '#e6f7ff'
                  : '#fff',
              verticalAlign: 'top',
            }"
            @click.stop="handleTd(tdElement, rowIndex + '-' + tdIndex)"
          >
            <slot name="tdElement" :tdElement="tdElement" :key="tableKey"></slot>
            <a-dropdown
              v-if="curTdIndex == rowIndex + '-' + tdIndex"
              :trigger="['click']"
              @click="HandleSetting(element.layout, rowIndex, tdIndex, row.list)"
            >
              <SettingOutlined style="position: absolute; right: 10px; bottom: 10px" />
              <template #overlay>
                <a-menu>
                  <a-menu-item>
                    <a
                      href="javascript:;"
                      @click="addLeftCol(element.layout, row.list, tdIndex, rowIndex)"
                      >左插入列</a
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a href="javascript:;" @click="addRightCol(element.layout, row.list, tdIndex)"
                      >右插入列</a
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a href="javascript:;" @click="addTopRow(element.layout, rowIndex, tdIndex)"
                      >上插入行</a
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a href="javascript:;" @click="addDownRow(element.layout, rowIndex)"
                      >下插入行</a
                    >
                  </a-menu-item>
                  <a-menu-divider />
                  <a-menu-item :disabled="disabledObj.right">
                    <a href="javascript:;" @click="mergeCol(row.list, tdIndex)">向右合并</a>
                  </a-menu-item>
                  <a-menu-item :disabled="disabledObj.down">
                    <a
                      href="javascript:;"
                      @click="mergeRow(element.layout, row.list, rowIndex, tdIndex)"
                      >向下合并</a
                    >
                  </a-menu-item>
                  <a-menu-divider />
                  <a-menu-item :disabled="!tdElement.colspan || tdElement.colspan < 2">
                    <a href="javascript:;" @click="splitCol(row.list, rowIndex, tdIndex)"
                      >拆分成列</a
                    >
                  </a-menu-item>
                  <a-menu-item :disabled="!tdElement.rowspan || tdElement.rowspan < 2">
                    <a
                      href="javascript:;"
                      @click="splitRow(element.layout, row.list, rowIndex, tdIndex)"
                      >拆分成行</a
                    >
                  </a-menu-item>
                  <a-menu-divider />
                  <a-menu-item :disabled="row.list.length == 1 || tdElement.colspan >= 2">
                    <a href="javascript:;" @click="deleteCol(element.layout, row.list, tdIndex)"
                      >删除当前列</a
                    >
                  </a-menu-item>
                  <a-menu-item :disabled="disabledObj.delRow">
                    <a href="javascript:;" @click="deleteRow(element.layout, row.list, rowIndex)"
                      >删除当前行</a
                    >
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script lang="ts" setup>
  import { SettingOutlined } from '@ant-design/icons-vue';
  import { cloneDeep, sortBy } from 'lodash-es';

  import { inject, onMounted, ref, watch, onUnmounted, Ref, nextTick } from 'vue';
  import { TableCell, TableTh } from '/@/components/Designer/src/types';

  const props = defineProps({
    element: {
      type: Object,
      required: true,
    },
  });
  const emit = defineEmits(['click']);
  const current = inject<Ref<number>>('current');
  const isCustomForm = inject<boolean>('isCustomForm', false);
  const designType = inject<string>('designType');
  const disabledObj = ref({
    right: false,
    down: false,
    delRow: false,
  });
  const tdMax = ref(0);
  const boxRef = ref();
  let curTdElement = inject<Ref<TableCell>>('tableCell', ref({}));
  let curThElement = inject<Ref<TableTh>>('tableTh', ref({}));
  const widthArr = ref<number[]>([]);
  const tableWidth = ref(0);
  const curThIndex = ref();
  const curTdIndex = ref();
  const tableKey = ref(0);
  onMounted(() => {
    tdMax.value = 0;
    props.element.layout[0].list.forEach((o) => {
      if (o.colspan >= 2) {
        tdMax.value = tdMax.value + o.colspan;
      } else {
        tdMax.value += 1;
      }
    });
    compulateWidth();
    window.onresize = () => {
      compulateWidth();
    };
    setTimeout(() => {
      tableKey.value++;
    }, 20);
  });
  onUnmounted(() => {
    window.onresize = null;
  });
  watch(
    () => current?.value,
    (val) => {
      if (
        (isCustomForm && val === 1) ||
        (!isCustomForm &&
          ((designType === 'data' && val === 1) || (designType !== 'data' && val === 0)))
      ) {
        compulateWidth();
      }
    },
  );
  watch(
    () => props.element.layout,
    async (val) => {
      tdMax.value = 0;
      val[0].list.forEach((o) => {
        if (o.colspan >= 2) {
          tdMax.value = tdMax.value + o.colspan;
        } else {
          tdMax.value += 1;
        }
      });

      compulateWidth();
    },
    { deep: true },
  );
  function compulateWidth() {
    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.layout.length; i++) {
        for (let k = 0; k < props.element.layout[i].list.length; k++) {
          let obj = props.element.layout[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 = 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);
        }
      }
    });
  }
  function handleTh(tdIndex) {
    for (let i = 0; i < props.element.layout.length; i++) {
      curThElement.value = {};
      for (let j = 0; j < props.element.layout[i].list.length; j++) {
        let obj = props.element.layout[i].list[j];
        if (obj.position[1] == tdIndex) {
          curThElement.value = obj;
          curThIndex.value = tdIndex;
          break;
        }
      }
      if (curThElement.value && Object.keys(curThElement.value).length > 0) break;
    }
    curTdElement.value = {};
    curTdIndex.value = null;
    emit('click');
  }
  function handleTd(el, tdIndex) {
    curTdElement.value = el;
    curThElement.value = {};
    curThIndex.value = null;
    curTdIndex.value = tdIndex;
    emit('click');
  }

  function addLeftCol(layout, list, idx, rowIndex) {
    if (idx == 0) {
      layout.forEach((o, i) => {
        o.list.splice(0, 0, {
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          position: [i, 0],
        });
        for (let j = 1; j < o.list.length; j++) {
          o.list[j].position[1] += 1;
        }
      });
    } else {
      addRightCol(layout, list, idx - 1);
    }
    curTdIndex.value = rowIndex + '-' + (idx + 1);
  }
  function addRightCol(layout, list, idx) {
    let curRowBox = 0;
    if (list[idx].colspan >= 2) {
      curRowBox = list[idx].position[1] + list[idx].colspan;
    } else {
      curRowBox = list[idx].position[1] + 1;
    } //当前格子之前的格子数

    let colObj: any = {}; //其他行格子数之和最接近curRowBox的格子所在索引
    let colArr: number[] = [];
    layout.forEach((o, i) => {
      let span = 0;
      for (let j = 0; j < o.list.length; j++) {
        if (o.list[j].colspan >= 2) {
          span = o.list[j].position[1] + o.list[j].colspan;
        } else {
          span = o.list[j].position[1] + 1;
        }

        if (span == curRowBox) {
          if (o.list[j].colspan >= 2) {
            span = o.list[j].position[1] + o.list[j].colspan;
          }
          colObj[i] = { index: j, num: span };
          break;
        } else if (span > curRowBox) {
          if (j - 1 < 0) {
            colObj[i] = { index: j, num: span };
          } else {
            if (o.list[j - 1].colspan >= 2) {
              span = o.list[j - 1].position[1] + o.list[j - 1].colspan;
            } else {
              span = o.list[j].position[1] > curRowBox ? curRowBox : o.list[j].position[1];
            }
            colObj[i] = { index: j - 1, num: span };
          }
          break;
        }
      }
      colArr.push(span);
    });

    let lastObj = colObj;

    layout.forEach((o, i) => {
      let index = 0;
      let pcol = 0;

      index = lastObj[i].index + 1;
      pcol = lastObj[i].num;

      o.list.splice(index, 0, {
        width: '',
        height: '',
        class: 'tableLayoutTd',
        children: [],
        position: [i, pcol],
      });
      o.list.forEach((k, j) => {
        if (j > index) {
          k.position[1] += 1;
        }
      });
    });
  }

  function addTopRow(layout, idx, tdIndex) {
    if (idx == 0) {
      let lastRow: any = [];
      for (let j = 0; j < tdMax.value; j++) {
        lastRow.push({
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          position: [0, j],
        });
      }
      layout.splice(0, 0, { list: lastRow });
      layout.forEach((o, i) => {
        o.list.forEach((k) => {
          k.position[0] = i;
        });
      });
    } else {
      addDownRow(layout, idx - 1);
    }
    curTdIndex.value = idx + 1 + '-' + layout[idx].list[tdIndex].position[1];
  }
  function addDownRow(layout, idx) {
    if (layout.length == idx + 1) {
      let lastRow: any = [];
      for (let j = 0; j < tdMax.value; j++) {
        lastRow.push({
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          position: [layout.length, j],
        });
      }
      layout.push({ list: lastRow });
    } else if (layout.length > idx + 1) {
      let newCol = {};
      let newRow = {};
      let arr: number[] = [];
      for (let i = 0; i < tdMax.value; i++) {
        let obj = layout[idx].list.find((o) => {
          return o.position[1] == i;
        });
        if (obj) {
          arr.push(i);
          let item = obj;
          if (item.rowspan >= 2) {
            if (!newRow[idx + item.rowspan]) {
              newRow[idx + item.rowspan] = { list: {} };
            }
            if (item.colspan >= 2) {
              for (let j = i; j < i + item.colspan; j++) {
                arr.push(j);
                newRow[idx + item.rowspan].list[j] = {
                  width: '',
                  height: '',
                  class: 'tableLayoutTd',
                  children: [],
                  position: [idx + item.rowspan, j],
                };
              }
            } else {
              newRow[idx + item.rowspan].list[i] = {
                width: '',
                height: '',
                class: 'tableLayoutTd',
                children: [],
                position: [idx + item.rowspan, i],
              };
            }
          } else {
            if (!newCol[idx + 1]) {
              newCol[idx + 1] = { list: [] };
            }
            if (item.colspan >= 2) {
              for (let j = i; j < i + item.colspan; j++) {
                arr.push(j);
                newCol[idx + 1].list.push({
                  width: '',
                  height: '',
                  class: 'tableLayoutTd',
                  children: [],
                  position: [idx + 1, j],
                });
              }
            } else {
              newCol[idx + 1].list.push({
                width: '',
                height: '',
                class: 'tableLayoutTd',
                children: [],
                position: [idx + 1, i],
              });
            }
          }
        } else if (!arr.includes(i)) {
          //往上找rowspan
          findRowSpan(layout, idx - 1, i, newRow, arr);
        }
      }
      layout.splice(idx + 1, 0, { list: newCol[idx + 1].list });
      for (let j = idx + 2; j < layout.length; j++) {
        for (let k = 0; k < layout[j].list.length; k++) {
          layout[j].list[k].position[0] += 1;
        }
      }

      for (let i in newRow) {
        for (let k in newRow[i].list) {
          layout[i].list.splice(k, 0, newRow[i].list[k]);
          layout[i].list = sortBy(layout[i].list, function (o) {
            return o.position[1];
          });
        }
      }
    }
  }
  function findRowSpan(layout, idx, i, newRow, arr) {
    if (idx < 0) return;
    let obj = layout[idx].list.find((o) => {
      return o.position[1] == i;
    });
    if (obj) {
      arr.push(i);
      let item = obj;
      if (item.rowspan >= 2) {
        if (!newRow[idx + item.rowspan]) {
          newRow[idx + item.rowspan] = { list: {} };
        }
        if (item.colspan >= 2) {
          for (let j = i; j < i + item.colspan; j++) {
            arr.push(j);
            newRow[idx + item.rowspan].list[j] = {
              width: '',
              height: '',
              class: 'tableLayoutTd',
              children: [],
              position: [idx + item.rowspan, j],
            };
          }
        } else {
          newRow[idx + item.rowspan].list[i] = {
            width: '',
            height: '',
            class: 'tableLayoutTd',
            children: [],
            position: [idx + item.rowspan, i],
          };
        }
      }
    } else {
      findRowSpan(layout, idx - 1, i, newRow, arr);
    }
  }

  function mergeCol(list, idx) {
    let colspan =
      list[idx].colspan >= 2
        ? list[idx + 1].colspan >= 2
          ? list[idx].colspan + list[idx + 1].colspan
          : list[idx].colspan + 1
        : list[idx + 1].colspan >= 2
        ? 1 + list[idx + 1].colspan
        : 2;
    list[idx].children = list[idx].children.concat(list[idx + 1].children);
    list[idx].colspan = colspan;
    list.splice(idx + 1, 1);
  }

  function mergeRow(layout, list, rowIndex, tdIndex) {
    let rowx = list[tdIndex].rowspan >= 2 ? list[tdIndex].rowspan : 1;
    let tdx = 0;
    layout[rowIndex + rowx].list.forEach((o, i) => {
      if (o.position[1] == list[tdIndex].position[1]) {
        tdx = i;
        list[tdIndex].children = list[tdIndex].children.concat(
          layout[rowIndex + rowx].list[i].children,
        );
        list[tdIndex].rowspan = rowx + (o.rowspan ? o.rowspan : 1);
      }
    });

    layout[rowIndex + rowx].list.splice(tdx, 1);
  }
  function deleteCol(layout, list, tdIndex) {
    let pcol = list[tdIndex].position[1];

    let colObj = findPcol(layout, pcol);

    for (let i in colObj) {
      let colspan = colObj[i].list[colObj[i].tdIdx].colspan;
      if (colspan >= 2) {
        let Tlist = colObj[i].list;
        let TtdIndex = colObj[i].tdIdx;
        let TrowIndex = Number(i);

        Tlist.splice(TtdIndex + 1, 0, {
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          rowspan: Tlist[TtdIndex].rowspan,
          position: [TrowIndex, pcol],
        });

        Tlist[TtdIndex].colspan = Tlist[TtdIndex].colspan - 1;
      }
    }

    for (let i = 0; i < layout.length; i++) {
      let tdidx = layout[i].list.findIndex((o) => {
        return o.position[1] == pcol;
      });

      if (tdidx >= 0) {
        layout[i].list.splice(tdidx, 1);
      }
      for (let j = 0; j < layout[i].list.length; j++) {
        if (layout[i].list[j].position[1] > pcol) {
          let clone = cloneDeep(layout[i].list[j]);
          clone.position[1] -= 1;
          layout[i].list.splice(j, 1, clone);
        }
      }
    }
  }
  function findPcol(layout, pcol) {
    let hasPcol = {}; //最接近pcol的格子
    for (let i = 0; i < layout.length; i++) {
      let arr: number[] = [];
      for (let j = 0; j < layout[i].list.length; j++) {
        if (layout[i].list[j].position[1] <= pcol) {
          arr.push(j);
        }
      }
      if (arr.length > 0) {
        hasPcol[i] = { tdIdx: arr[arr.length - 1], list: layout[i].list };
      }
    }
    return hasPcol;
  }

  function deleteRow(layout, list, rowIndex) {
    let arr: number[] = [];
    for (let i = 0; i < list.length; i++) {
      let item = list[i];
      if (item.rowspan >= 2) {
        layout[rowIndex + 1].list.splice(i, 0, {
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          rowspan: item.rowspan - 1,
          colspan: item.colspan,
          position: [rowIndex, item.position[1]],
        });
        if (item.colspan >= 2) {
          for (let j = 0; j < item.colspan; j++) {
            arr.push(item.position[1] + j);
          }
        } else {
          arr.push(item.position[1]);
        }
      } else if (item.colspan >= 2) {
        for (let j = 0; j < item.colspan; j++) {
          arr.push(item.position[1] + j);
        }
      } else {
        for (let i = 0; i < tdMax.value; i++) {
          if (item.position[1] == i) {
            arr.push(item.position[1]);
          }
        }
      }
    }

    for (let i = 0; i < tdMax.value; i++) {
      if (!arr.includes(i)) {
        //往上找rowspan
        findTopRow(layout, rowIndex - 1, i, arr);
      }
    }

    layout.splice(rowIndex, 1);
    layout.forEach((o, i) => {
      o.list.forEach((k) => {
        k.position[0] = i;
      });
    });
    layout[rowIndex].list = sortBy(layout[rowIndex].list, function (o) {
      return o.position[1];
    });
  }
  function findTopRow(layout, idx, i, arr) {
    if (idx < 0) return;
    let index = layout[idx].list.findIndex((o) => {
      return o.position[1] == i;
    });

    if (index >= 0) {
      let item = layout[idx].list[index];
      if (item.rowspan >= 2) {
        item.rowspan -= 1;
        layout[idx].list.splice(index, 1, item);
        if (item.colspan >= 2) {
          for (let j = 0; j < item.colspan; j++) {
            arr.push(item.position[1] + j);
          }
        } else {
          arr.push(item.position[1]);
        }
      }
    } else {
      findTopRow(layout, idx - 1, i, arr);
    }
  }
  function splitCol(list, rowIndex, tdIndex) {
    if (list[tdIndex].colspan >= 2) {
      for (let j = tdIndex + 1; j < list[tdIndex].colspan + tdIndex; j++) {
        list.splice(j, 0, {
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          rowspan: list[tdIndex].rowspan,
          position: [rowIndex, j],
        });
      }
      list[tdIndex].colspan = '';
    }
  }
  function splitRow(layout, list, rowIndex, tdIndex) {
    if (list[tdIndex].rowspan >= 2) {
      for (let j = rowIndex + 1; j < list[tdIndex].rowspan + rowIndex; j++) {
        let index = layout[j].list.findIndex((k) => {
          return k.position[1] > list[tdIndex].position[1];
        });

        layout[j].list.splice(index, 0, {
          width: '',
          height: '',
          class: 'tableLayoutTd',
          children: [],
          colspan: list[tdIndex].colspan,
          position: [j, list[tdIndex].position[1]],
        });
      }
      list[tdIndex].rowspan = '';
    }
  }
  function mergeDownDisabled(layout, rowIndex, tdIndex, list) {
    let flag = false;
    let rowx = list[tdIndex].rowspan >= 2 ? list[tdIndex].rowspan : 1;
    // 下一行合并列相同的就可以合并
    if (layout[rowIndex + rowx]) {
      let obj = layout[rowIndex + rowx].list.find((o) => {
        return o.position[1] == list[tdIndex].position[1];
      });
      if (obj) {
        if (list[tdIndex].colspan && list[tdIndex].colspan == obj.colspan) {
          flag = false;
        } else if (
          (!list[tdIndex].colspan || list[tdIndex].colspan < 2) &&
          (!obj.colspan || obj.colspan < 2)
        ) {
          flag = false;
        } else {
          flag = true;
        }
      } else {
        flag = true;
      }
    } else {
      flag = true;
    }

    return flag;
  }

  function mergeRightDisabled(tdIndex, list) {
    let flag = false;
    if (tdIndex == list.length - 1) {
      flag = true;
    } else if (list[tdIndex].rowspan >= 2) {
      if (list[tdIndex + 1]?.rowspan >= 2) {
        if (list[tdIndex + 1].rowspan == list[tdIndex].rowspan) {
          flag = false;
        } else {
          flag = true;
        }
      } else {
        flag = true;
      }
    } else if (!list[tdIndex].rowspan || list[tdIndex].rowspan < 2) {
      if (list[tdIndex + 1]?.rowspan >= 2) {
        flag = true;
      } else {
        flag = false;
        if (list[tdIndex + 1].position[1] > list[tdIndex].position[1] + 1) {
          flag = true;
          if (list[tdIndex].colspan >= 2) {
            flag = false;
          }
        }
      }
    } else {
      flag = false;
    }
    return flag;
  }

  function delRowDiasbled(layout) {
    let count = 0;
    layout.forEach((o) => {
      if (o.list.length > 0) {
        count += 1;
      }
    });
    return count == 1 ? true : false;
  }

  function HandleSetting(layout, rowIndex, tdIndex, list) {
    disabledObj.value.down = mergeDownDisabled(layout, rowIndex, tdIndex, list);
    disabledObj.value.right = mergeRightDisabled(tdIndex, list);
    disabledObj.value.delRow = delRowDiasbled(layout);
  }
</script>
