<template>
  <div class="content-table-layer">
    <table class="content-table" ref="tableRef">
      <tr class="header">
        <th
          class="sel-th"
          v-for="(col, colIndex) in rows[0]"
          @click="select = { col: colIndex }"
          :class="{ active: colIndex === select.col }"
        >
          <el-button type="primary" plain size="small" @click.stop="delColumn(colIndex)">
            <el-icon><Minus /></el-icon>
          </el-button>
        </th>
        <td></td>
      </tr>
      <tr v-for="(row, rowIndex) in rows" class="row" :key="rowIndex">
        <td
          v-for="(col, colIndex) in row"
          class="col"
          :key="colIndex"
          @click="inputPos = [rowIndex, colIndex]"
        >
          <input
            :ref="(dom: any) => inputRef = dom"
            @blur="inputPos = null"
            v-if="inputPos && rowIndex === inputPos[0] && colIndex === inputPos[1]"
            :value="col"
            :style="getBound(rowIndex, colIndex)"
            @change="ev => setColValue(rowIndex, colIndex, (ev.target as any).value)"
          />
          <span v-else :style="getBound(rowIndex, colIndex)">{{ col || "" }}&nbsp;</span>
        </td>
        <th
          class="sel-th del-col"
          @click="select = { row: rowIndex }"
          :class="{ active: rowIndex === select.row }"
        >
          <div style="width: 100px"></div>
          <el-button type="primary" plain size="small" @click="delRow(rowIndex)">
            <el-icon><Minus /></el-icon>
          </el-button>
        </th>
      </tr>
    </table>
  </div>
  <div class="setter" v-if="selectValue">
    <el-form-item :label="selectValue.label">
      <el-input-number
        :modelValue="selectValue.value"
        @update:modelValue="changeSelectValue"
        :min="24"
        :max="1000"
        size="small"
        controls-position="right"
      />
    </el-form-item>
  </div>
  <div class="add-row-layout">
    <el-button type="primary" @click="addRow">
      <el-icon><Plus /></el-icon> 行
    </el-button>
    <el-button type="primary" @click="addCloumn">
      <el-icon><Plus /></el-icon> 列
    </el-button>
  </div>
</template>

<script setup lang="ts">
import { ElMessage } from "element-plus";
import { computed, nextTick, ref, watchEffect } from "vue";
import { QuiskExpose } from "@/helper/mount";

export type EshapeTableContent = {
  width: number;
  height: number;
  value: string;
  colIndex: number;
  rowIndex: number;
}[];

const props = defineProps<{ content: EshapeTableContent; track?: boolean }>();
const bindContent = ref(props.content.map((item) => ({ ...item })));
const inputPos = ref<[number, number] | null>(null);
const inputRef = ref<HTMLInputElement>();
const select = ref<{ col?: number; row?: number }>({});

const selectValue = computed(() => {
  if (Object.keys(select.value).length === 0) return;
  const isCol = "col" in select.value;
  const item = bindContent.value.find((item) =>
    isCol ? item.colIndex === select.value.col : item.rowIndex === select.value.row
  )!;
  if (item) {
    return isCol
      ? { label: "列宽", value: item.width }
      : { label: "行高", value: item.height };
  }
});

const changeSelectValue = (val: number) => {
  const isCol = "col" in select.value;
  bindContent.value
    .filter((item) =>
      isCol ? item.colIndex === select.value.col : item.rowIndex === select.value.row
    )
    .forEach((item) => {
      if (isCol) {
        item.width = val;
      } else {
        item.height = val;
      }
    });
};

const getBound = (rowIndex, colIndex) => {
  const item = bindContent.value.find(
    (item) => item.rowIndex === rowIndex && item.colIndex === colIndex
  );
  const bound = [170, 25 - 2];
  if (item && item.width && item.height) {
    bound[0] = item.width;
    bound[1] = item.height;
  } else if (colIndex === 0) {
    bound[0] = 90;
  }

  return {
    width: bound[0] + "px",
    "min-height": bound[1] + "px",
  };
};

watchEffect(
  () => {
    if (inputRef.value) {
      inputRef.value.focus();
    }
  },
  { flush: "post" }
);

const delRow = (rowIndex: number) => {
  if (rows.value.length === 1) {
    ElMessage.error("表格最少需要保留一行！");
  } else {
    bindContent.value = bindContent.value
      .filter((item) => item.rowIndex !== rowIndex)
      .map((item) => {
        if (item.rowIndex > rowIndex) {
          return { ...item, rowIndex: item.rowIndex - 1 };
        } else {
          return item;
        }
      });
  }
};

const delColumn = (columnIndex: number) => {
  if (rows.value[0].length === 1) {
    ElMessage.error("表格最少需要保留一列！");
  } else {
    console.log(columnIndex, bindContent.value);
    bindContent.value = bindContent.value
      .filter((item) => item.colIndex !== columnIndex)
      .map((item) => {
        if (item.colIndex > columnIndex) {
          return { ...item, colIndex: item.colIndex - 1 };
        } else {
          return item;
        }
      });
    console.log(columnIndex, bindContent.value);
  }
};

const addRow = () => {
  const colSize = rows.value[0].length;
  const rowSize = rows.value.length;
  for (let i = 0; i < colSize; i++) {
    bindContent.value.push({
      width: 0,
      height: 0,
      colIndex: i,
      rowIndex: rowSize,
      value: "",
    });
  }
  nextTick(updateTableContent);
};
const addCloumn = () => {
  const colSize = rows.value[0].length;
  const rowSize = rows.value.length;
  for (let i = 0; i < rowSize; i++) {
    bindContent.value.push({
      width: 0,
      height: 0,
      colIndex: colSize,
      rowIndex: i,
      value: "",
    });
  }
  nextTick(updateTableContent);
  // for (let i = 0; i < colSize; i++) {
  //   bindContent.value.push({
  //     width: 0,
  //     height: 0,
  //     colIndex: i,
  //     rowIndex: rowSize,
  //     value: "",
  //   });
  // }
};

const setColValue = (rowIndex: number, colIndex: number, val: string) => {
  const item = bindContent.value.find(
    (item) => item.rowIndex === rowIndex && item.colIndex === colIndex
  )!;
  item.value = val;
};

const rows = computed(() => {
  const rows: string[][] = [];
  bindContent.value.forEach((item) => {
    rows[item.rowIndex] = rows[item.rowIndex] || [];
    rows[item.rowIndex][item.colIndex] = item.value;
  });
  return rows;
});

const tableRef = ref<HTMLTableElement>();
const updateTableContent = () => {
  const dom = tableRef.value!;
  const rows = Array.from(dom.querySelectorAll(".row"));
  for (let i = 0; i < rows.length; i++) {
    const cols = Array.from(rows[i].querySelectorAll(".col"));

    for (let j = 0; j < cols.length; j++) {
      const col = cols[j] as HTMLElement;
      const item = bindContent.value.find(
        (item) => item.rowIndex === i && item.colIndex === j
      )!;
      item.width = col.offsetWidth;
      item.height = col.offsetHeight;
    }
  }
};

defineExpose<QuiskExpose>({
  submit() {
    updateTableContent();
    return bindContent.value;
  },
});
</script>

<style lang="scss" scoped>
.content-table {
  margin: 0 auto;
  border-collapse: collapse;
  --border-color: #f0f2f5;
  margin-bottom: 10px;
  table-layout: fixed;

  th {
    background: #fafafb;
  }

  tr:first-child {
    th,
    td {
      border-top: 1px solid var(--border-color);
    }
  }
  th:first-child,
  td:first-child {
    border-left: 1px solid var(--border-color);
  }
  th,
  td {
    border-right: 1px solid var(--border-color);
    border-bottom: 1px solid var(--border-color);
    text-align: center;
  }

  .col {
    cursor: pointer;

    &:hover {
      background-color: rgba(133, 194, 255, 0.1);
    }
    span,
    input {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      font-size: 12px;
      width: 100%;
      height: 100%;
      border: none;
      text-align: center;
      line-height: 24px;
    }
    span {
      word-break: break-all;
    }
  }
  .col:hover {
    background-color: rgba(133, 194, 255, 0.1);
  }
  .sel-th {
    cursor: pointer;
  }
  .active {
    box-shadow: 0 0 0 1px var(--el-color-primary) inset;
  }
}

.add-row-layout {
  text-align: center;
}

.content-table-layer {
  overflow: auto;
  text-align: center;
}
.setter {
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>
