<template>
  <div ref="wrapRef" :class="getWrapperClass">
    <BasicForm
      ref="formRef"
      submitOnReset
      v-bind="getFormProps"
      v-if="getBindValues.useSearchForm"
      :tableAction="tableAction"
      @register="registerForm"
      @submit="handleSearchInfoChange"
      @advanced-change="redoHeight"
    >
      <template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
        <slot :name="item" v-bind="data || {}"></slot>
      </template>
    </BasicForm>
    <div v-if="props.showLayout">
      <Row :gutter="16" v-if="props.isShowTable">
        <Col :span="16" :push="8"> <slot name="showEcharts"></slot></Col>
        <Col :span="8" :pull="16">
          <Table
            ref="tableElRef"
            v-bind="getBindValues"
            :rowClassName="getRowClassName"
            v-show="getEmptyDataIsShowTable"
            @change="handleTableChange"
            @resize-column="setColumnWidth"
            @expand="handleTableExpand"
          >
            <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
              <slot :name="item" v-bind="data || {}"></slot>
            </template>
            <template #headerCell="{ column }">
              <slot name="headerCell" v-bind="{ column }">
                <HeaderCell :column="column" />
              </slot>
            </template>
            <template #bodyCell="data">
              <slot name="bodyCell" v-bind="data || {}"></slot>
            </template>
          </Table>
        </Col>
      </Row>
      <div v-else><slot name="noTableContent"></slot></div>
    </div>
    <div v-else>
      <Table
        :hideOnSinglePage="true"
        ref="tableElRef"
        v-bind="getBindValues"
        :rowClassName="getRowClassName"
        v-show="getEmptyDataIsShowTable"
        @change="handleTableChange"
        @resize-column="setColumnWidth"
        @expand="handleTableExpand"
      >
        <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
        <template #headerCell="{ column }">
          <slot name="headerCell" v-bind="{ column }">
            <HeaderCell :column="column" />
          </slot>
        </template>
        <template #bodyCell="data">
          <slot name="bodyCell" v-bind="data || {}"></slot>
        </template>
      </Table>
    </div>
  </div>
</template>
<script lang="ts" setup>
import type {
  BasicTableProps,
  TableActionType,
  SizeType,
  ColumnChangeParam,
} from "./types/table";
import { ref, computed, unref, toRaw, inject, watch, useAttrs, useSlots } from "vue";
import { Table, Row, Col } from "ant-design-vue";
import { BasicForm, useForm } from "@/components/Form";
import { PageWrapperFixedHeightKey } from "@/enums/pageEnum";
import HeaderCell from "./components/HeaderCell.vue";
import { InnerHandlers, InnerMethods } from "./types/table";
import { usePagination } from "./hooks/usePagination";
import { useColumns } from "./hooks/useColumns";
import { useDataSource } from "./hooks/useDataSource";
import { useLoading } from "./hooks/useLoading";
import { useRowSelection } from "./hooks/useRowSelection";
import { useTableScroll } from "./hooks/useTableScroll";
import { useTableScrollTo } from "./hooks/useScrollTo";
import { useCustomRow } from "./hooks/useCustomRow";
import { useTableStyle } from "./hooks/useTableStyle";
import { useTableHeader } from "./hooks/useTableHeader";
import { useTableExpand } from "./hooks/useTableExpand";
import { createTableContext } from "./hooks/useTableContext";
import { useTableFooter } from "./hooks/useTableFooter";
import { useTableForm } from "./hooks/useTableForm";
import { useDesign } from "@/hooks/web/useDesign";
import { omit, debounce } from "lodash-es";
import { useElementSize } from "@vueuse/core";
import { basicProps } from "./props";
import { isFunction } from "@/utils/is";

defineOptions({ name: "BasicTable" });

const props = defineProps(basicProps);

const emit = defineEmits([
  "fetch-success",
  "fetch-error",
  "selection-change",
  "register",
  "row-click",
  "row-dbClick",
  "row-contextmenu",
  "row-mouseenter",
  "row-mouseleave",
  "edit-end",
  "edit-cancel",
  "edit-row-end",
  "edit-change",
  "expanded-rows-change",
  "change",
  "columns-change",
]);

const attrs = useAttrs();
const slots = useSlots();

const tableElRef = ref(null);
const tableData = ref([]);

const wrapRef = ref(null);
const formRef = ref(null);
const innerPropsRef = ref<Partial<BasicTableProps>>();

const { height } = useElementSize(wrapRef);

const { prefixCls } = useDesign("basic-table");
const [registerForm, formActions] = useForm();

const getProps = computed(() => {
  return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
});

const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);

const { getLoading, setLoading } = useLoading(getProps);
const {
  getPaginationInfo,
  getPagination,
  setPagination,
  setShowPagination,
  getShowPagination,
} = usePagination(getProps);

const {
  getRowSelection,
  getRowSelectionRef,
  getSelectRows,
  setSelectedRows,
  clearSelectedRowKeys,
  getSelectRowKeys,
  deleteSelectRowByKey,
  setSelectedRowKeys,
} = useRowSelection(getProps, tableData, emit);

const {
  handleTableChange: onTableChange,
  getDataSourceRef,
  getDataSource,
  getRawDataSource,
  getSearchInfo,
  setTableData,
  updateTableDataRecord,
  deleteTableDataRecord,
  insertTableDataRecord,
  findTableDataRecord,
  fetch,
  getRowKey,
  reload,
  getAutoCreateKey,
  updateTableData,
} = useDataSource(
  getProps,
  {
    tableData,
    getPaginationInfo,
    setLoading,
    setPagination,
    getFieldsValue: formActions.getFieldsValue,
    clearSelectedRowKeys,
  },
  emit
);

function handleTableChange(pagination: any, filters: any, sorter: any, extra: any) {
  onTableChange(pagination, filters, sorter);
  emit("change", pagination, filters, sorter);
  // 解决通过useTable注册onChange时不起作用的问题
  const { onChange } = unref(getProps);
  onChange && isFunction(onChange) && onChange(pagination, filters, sorter, extra);
}

const {
  getViewColumns,
  getColumns,
  setCacheColumnsByField,
  setCacheColumns,
  setColumnWidth,
  setColumns,
  getColumnsRef,
  getCacheColumns,
} = useColumns(getProps, getPaginationInfo);

const { getScrollRef, redoHeight } = useTableScroll(
  getProps,
  tableElRef,
  getColumnsRef,
  getRowSelectionRef,
  getDataSourceRef,
  wrapRef,
  formRef
);
const debounceRedoHeight = debounce(redoHeight, 50);

const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef);

const { customRow } = useCustomRow(getProps, {
  setSelectedRowKeys,
  getSelectRowKeys,
  clearSelectedRowKeys,
  getAutoCreateKey,
  emit,
});

const { getRowClassName } = useTableStyle(getProps, prefixCls);

const {
  getExpandOption,
  expandAll,
  expandRows,
  collapseRows,
  collapseAll,
  handleTableExpand,
} = useTableExpand(getProps, tableData, emit);

const handlers: InnerHandlers = {
  onColumnsChange: (data: ColumnChangeParam[]) => {
    emit("columns-change", data);
    // support useTable
    unref(getProps).onColumnsChange?.(data);
  },
};

const methods: InnerMethods = {
  clearSelectedRowKeys,
  getSelectRowKeys,
};

const { getHeaderProps } = useTableHeader(getProps, slots, handlers, methods);

const { getFooterProps } = useTableFooter(
  getProps,
  getScrollRef,
  tableElRef,
  getDataSourceRef
);

const {
  getFormProps,
  replaceFormSlotKey,
  getFormSlotKeys,
  handleSearchInfoChange,
} = useTableForm(getProps, slots, fetch, getLoading);

const getBindValues = computed(() => {
  const dataSource = unref(getDataSourceRef);
  let propsData: any = {
    ...attrs,
    customRow,
    ...unref(getProps),
    ...unref(getHeaderProps),
    scroll: unref(getScrollRef),
    loading: unref(getLoading),
    tableLayout: "fixed",
    rowSelection: unref(getRowSelectionRef),
    rowKey: unref(getRowKey),
    columns: toRaw(unref(getViewColumns)),
    pagination: toRaw(unref(getPaginationInfo)),
    dataSource,
    footer: unref(getFooterProps),
    ...unref(getExpandOption),
  };
  // if (slots.expandedRowRender) {
  //   propsData = omit(propsData, 'scroll');
  // }

  propsData = omit(propsData, ["class", "onChange"]);
  return propsData;
});

const getWrapperClass = computed(() => {
  const values = unref(getBindValues);
  return [
    prefixCls,
    attrs.class,
    {
      [`${prefixCls}-form-container`]: values.useSearchForm,
      [`${prefixCls}--inset`]: values.inset,
    },
  ];
});

const getEmptyDataIsShowTable = computed(() => {
  const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
  if (emptyDataIsShowTable || !useSearchForm) {
    return true;
  }
  return !!unref(getDataSourceRef).length;
});

watch(height, () => {
  unref(isFixedHeightPage) && props.canResize && debounceRedoHeight();
});

function setProps(props: Partial<BasicTableProps>) {
  innerPropsRef.value = { ...unref(innerPropsRef), ...props };
}
// const clickSubmit =()=>{
//   formActions.submit
// }
const tableAction: TableActionType = {
  reload,
  // clickSubmit,
  getSelectRows,
  setSelectedRows,
  clearSelectedRowKeys,
  getSelectRowKeys,
  deleteSelectRowByKey,
  setPagination,
  setTableData,
  updateTableDataRecord,
  deleteTableDataRecord,
  insertTableDataRecord,
  findTableDataRecord,
  redoHeight,
  setSelectedRowKeys,
  setColumns,
  setLoading,
  getDataSource,
  getRawDataSource,
  getSearchInfo,
  setProps,
  getRowSelection,
  getPaginationRef: getPagination,
  getColumns,
  getCacheColumns,
  emit,
  updateTableData,
  setShowPagination,
  getShowPagination,
  setCacheColumnsByField,
  expandAll,
  collapseAll,
  expandRows,
  collapseRows,
  scrollTo,
  getSize: () => {
    return unref(getBindValues).size as SizeType;
  },
  setCacheColumns,
};
createTableContext({ ...tableAction, wrapRef, getBindValues });

emit("register", tableAction, formActions);

defineExpose({ tableElRef, ...tableAction });
</script>
<style lang="less">
@border-color: #cecece4d;

@prefix-cls: ~"@{namespace}-basic-table";

[data-theme="dark"] {
  .ant-table-tbody > tr:hover.ant-table-row-selected > td,
  .ant-table-tbody > tr.ant-table-row-selected td {
    background-color: #262626;
  }
}

.@{prefix-cls} {
  max-width: 100%;
  height: 100%;

  &-row__striped {
    td {
      background-color: @app-content-background !important;
    }
  }

  &-form-container {
    padding: 16px;

    .ant-form {
      width: 100%;
      margin-bottom: 16px;
      padding: 12px 10px 6px;
      border-radius: 8px;
      background-color: @component-background;
    }
  }

  .ant-table-cell {
    .ant-tag {
      margin-right: 0;
    }
  }

  .ant-table-wrapper {
    padding: 6px;
    border-radius: 8px;
    background-color: @component-background;

    .ant-table-title {
      min-height: 40px;
      padding: 0 0 8px !important;
    }

    .ant-table.ant-table-bordered {
      .ant-table-title {
        border: none !important;
      }

      /** 修复在开启bordered情况下 有一条竖线 */
      .ant-table-container {
        border-inline-start: 0;
      }
    }
  }

  .ant-table {
    width: 100%;
    overflow-x: hidden;

    &-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 8px 6px;
      border-bottom: none;
    }

    //.ant-table-tbody > tr.ant-table-row-selected td {
    //background-color: fade(@primary-color, 8%) !important;
    //}
  }

  .ant-table-wrapper .ant-pagination {
    margin: 10px 0 0;
  }

  .ant-table-footer {
    padding: 0;

    .ant-table-wrapper {
      padding: 0;
    }

    table {
      border: none !important;
    }

    .ant-table-body {
      overflow-x: hidden !important;
      //  overflow-y: scroll !important;
    }

    td {
      padding: 12px 8px;
    }
  }

  &--inset {
    .ant-table-wrapper {
      padding: 0;
    }
  }
}
</style>
