<script lang="ts" setup>
import TableHeader from "./TableHeader.vue";
import TableMain from "./TableMain.vue";
import type { SearcherProp } from "../search-bar/SearchBarType";
import type { ToolButtonProp } from "../table-tool-bar/TableToolBarType";
import type { PropType } from "vue";
import { get } from "@/common/http/request";
interface Emits {
  (e: "data-loaded", data: any[]): void;
  (e: "expand-change", row: any, expandedRows: any[]): void;
}

const props = defineProps({
  searchers: Array as PropType<SearcherProp[]>,
  toolButtons: Array as PropType<ToolButtonProp[]>,
  data: Array,
  url: String,
  parse: Function,
  expandRowKeys: Array as PropType<(string | number)[]>,
  rowKey: { type: String, default: "id" },
});
const emit = defineEmits<Emits>();
const tableMainRef = ref<InstanceType<typeof TableMain> | null>(null);
const tableHeaderEl = ref<HTMLElement | null>(null);
const tableMainHostEl = ref<HTMLElement | null>(null);
const headerBaseHeight = ref(0);
const headerExtraOffset = ref(0);
const tableMainHeight = ref(0);
const page = ref(1);
const pageSize = ref(30);
const total = ref(0);
const searcherParams = ref({});
const tableData = ref<any[]>([]);
const updatePage = () => loadData();
const searchClick = () => loadData();

const loadData = async () => {
  if (props.data !== undefined) {
    total.value = props.data.length;
    tableData.value = props.data.slice(
      (page.value - 1) * pageSize.value,
      Math.min(page.value * pageSize.value, props.data.length)
    );
    onDataLoaded(tableData.value);
  }
  if (props.url !== undefined) {
    const params = new URLSearchParams();
    for (const [key, value] of Object.entries(searcherParams.value)) {
      params.append(key, String(value));
    }
    params.append("page", page.value.toString());
    params.append("pageSize", pageSize.value.toString());
    const urlRawData = await get(props.url, params).then(res => res.data);
    const urlData = props.parse === undefined ? urlRawData : props.parse(urlRawData);
    total.value = urlData.total;
    tableData.value = urlData.records;
    onDataLoaded(tableData.value);
  }
};

// 数据处理完成后的回调
const onDataLoaded = (data: any[]) => {
  emit("data-loaded", data);
};

const handleExpandChange = (row: any, expandedRows: any[]) => {
  emit("expand-change", row, expandedRows);
};

const recomputeTableHeight = () => {
  if (!tableMainHostEl.value) return;
  const top = tableMainHostEl.value.getBoundingClientRect().top;
  // 预留一点底部空隙，避免贴边导致分页视觉上“出屏”
  const paddingBottom = 12;
  const h = Math.floor(window.innerHeight - top - paddingBottom);
  tableMainHeight.value = Math.max(240, h);
};

defineExpose({
  reload: loadData,
  tableMainRef,
  toggleRowExpansion: (row: any, expanded?: boolean) => {
    tableMainRef.value?.toggleRowExpansion(row, expanded);
  },
  sort: (field: string, order: string) => {
    tableMainRef.value?.tableRef?.sort(field, order);
  },
});

onMounted(async () => {
  await loadData();

  await nextTick();
  if (tableHeaderEl.value) {
    headerBaseHeight.value = tableHeaderEl.value.getBoundingClientRect().height;
  }
  recomputeTableHeight();

  if (tableHeaderEl.value && "ResizeObserver" in window) {
    const ro = new ResizeObserver(entries => {
      const h = entries[0]?.contentRect?.height ?? 0;
      headerExtraOffset.value = Math.max(0, Math.round(h - headerBaseHeight.value));
      // 表头换行会影响 TableMain 的 top，需要同步重算可用高度
      requestAnimationFrame(recomputeTableHeight);
    });
    ro.observe(tableHeaderEl.value);
    onBeforeUnmount(() => ro.disconnect());
  }

  window.addEventListener("resize", recomputeTableHeight);
  onBeforeUnmount(() => window.removeEventListener("resize", recomputeTableHeight));
});
</script>
<template>
  <div ref="tableHeaderEl">
    <TableHeader
      v-if="searchers !== undefined"
      :searchers="searchers"
      :tool-buttons="toolButtons"
      v-model:searcher-params="searcherParams"
      :search-click="searchClick"
    >
      <template #tool-button><slot name="tool-button"></slot></template>
    </TableHeader>
  </div>
  <div ref="tableMainHostEl">
    <TableMain
      ref="tableMainRef"
      :data="tableData"
      :total="total"
      :update-page="updatePage"
      :container-height="tableMainHeight"
      :extra-offset="headerExtraOffset"
      v-model:page="page"
      v-model:page-size="pageSize"
      :expand-row-keys="expandRowKeys"
      :row-key="rowKey"
      @expand-change="handleExpandChange"
    >
      <template #columns><slot name="columns"></slot></template>
    </TableMain>
  </div>
</template>

<style scoped>
:deep(.el-table) {
  font-size: 13px;
}

:deep(.el-table th.el-table__cell) {
  font-weight: 600;
  background-color: var(--el-fill-color-light);
}

:deep(.el-pagination) {
  justify-content: flex-end;
}

:deep(.el-pagination.is-background .el-pager li) {
  font-weight: 500;
}
</style>
