import { GridModel } from '@ibiz-template/model';
import { useGridController, useNamespace } from '@ibiz-template/vue-util';
import {
  computed,
  defineComponent,
  getCurrentInstance,
  h,
  onUnmounted,
  PropType,
  Ref,
  ref,
  watch,
} from 'vue';
import { IModal } from '@ibiz-template/runtime';
import { AppGridPagination } from '@/components/common';
import {
  useAppGridPagination,
  useITableColumns,
  useITableEvent,
} from './grid-control.util';
import '@ibiz-template/theme/style/components/widgets/grid/grid.scss';

export const GridControl = defineComponent({
  props: {
    modelData: GridModel,
    context: { type: Object as PropType<IContext>, required: true },
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    /**
     * 表格行数据默认激活模式
     * - 0 不激活
     * - 1 单击激活
     * - 2 双击激活(默认值)
     *
     * @type {(number | 0 | 1 | 2)}
     */
    gridRowActiveMode: { type: Number, default: 2 },
    modal: { type: Object as PropType<IModal> },
  },
  setup(props) {
    const { proxy } = getCurrentInstance()!;

    const ns = useNamespace('grid');
    const c = useGridController(
      proxy,
      props.modelData!,
      props.context!,
      props.params,
    );

    // 部件参数
    const controlParam = c.model.source.getPSControlParam();

    // 是否不自适应最后一列
    const isNotFlex = controlParam?.ctrlParams?.IS_NOT_FLEX === 'true';

    // 表格组件
    const grid = ref();

    const [columns] = useITableColumns(c);
    const { onRowClick, onDbRowClick, onSelectionChange, onSortChange } =
      useITableEvent(c);
    const { onPageChange, onPageReset, onPageSizeChange } =
      useAppGridPagination(c);

    const highlight = computed(() => {
      const ctrlParams =
        props.modelData?.source.getPSControlParam()?.ctrlParams;
      return ctrlParams?.HIGHLIGHT !== 'false';
    });

    let timer: number | null = null;

    // iView表格单击行选中没有，必须手动调用选中方法
    const onUIRowClick = (data: IData, index: number) => {
      if (timer != null) {
        window.clearTimeout(timer);
      }
      timer = window.setTimeout(() => {
        const gridInstance: IData | undefined = proxy.$refs.grid;
        if (gridInstance) {
          const selectedItem = c.selectedData.find(
            item => item.srfkey === data.srfkey,
          );
          if (selectedItem) {
            gridInstance.clearCurrentRow();
          }
          if (gridInstance.toggleSelect) {
            gridInstance.toggleSelect(index);
          }
        }
        onRowClick(data);
      }, 300);
    };

    const onUIDbRowClick = (data: IData) => {
      if (timer != null) {
        window.clearTimeout(timer);
      }
      const gridInstance: IData | undefined = proxy.$refs.grid;
      if (gridInstance) {
        const selectedItem = c.selectedData.find(
          item => item.srfkey === data.srfkey,
        );
        if (!selectedItem) {
          gridInstance.clearCurrentRow();
        }
      }
      onDbRowClick(data);
    };

    // 给到iView table组件的高度
    const tableHeight = ref(0);

    // 表格外层div的引用
    const gridRef: Ref<HTMLElement | null> = ref(null);

    // 表格分页组件的引用
    const girdPaginationRef: Ref<InstanceType<
      typeof AppGridPagination
    > | null> = ref(null);

    // 浏览器ResizeObserver对象
    let resizeObserver: ResizeObserver | null = null;

    // 上次监听到的表格外层div高度，一旦发生变化就重新计算
    let lastGridHeight = 0;

    // 计算表格高度（用于固定头部）
    const calcGridHeight = () => {
      // 不是嵌入视图里的表格才去算高度
      if (gridRef.value && props.modal?.mode !== 'EMBED') {
        if (c.model.source.enablePagingBar && girdPaginationRef.value) {
          const gridPage = girdPaginationRef.value.$el as HTMLElement;
          const gridPageHeight =
            gridPage.offsetHeight +
            parseFloat(window.getComputedStyle(gridPage).paddingTop);
          tableHeight.value = gridRef.value.offsetHeight - gridPageHeight;
        } else {
          tableHeight.value = gridRef.value.offsetHeight;
        }
      }
      // 如果模型配置了高度走配置的
      if (c.model.source.height > 0) {
        tableHeight.value = c.model.source.height;
      }
    };

    watch(gridRef, (newVal, oldVal) => {
      if (newVal && newVal !== oldVal) {
        calcGridHeight();
        if (window.ResizeObserver && gridRef.value) {
          resizeObserver = new ResizeObserver(entries => {
            // 处理组件高度变化
            const height = entries[0].contentRect.height;
            if (height !== lastGridHeight) {
              calcGridHeight();
              lastGridHeight = height;
            }
          });
          resizeObserver.observe(gridRef.value);
        }
      }
    });

    onUnmounted(() => {
      // 在组件销毁前取消 ResizeObserver 的观察
      if (resizeObserver) {
        resizeObserver.disconnect();
      }
    });

    const tableData = computed(() => {
      const data = c.items.map((item: IData) => {
        // eslint-disable-next-line no-param-reassign
        item._checked = c.selectedData.some(
          (selected: IData) => selected.srfkey === item.srfkey,
        );
        return item;
      });
      if (!data.length) {
        return data;
      }
      data.unshift({
        hiddenRow: true,
        _checked: c.items.every((item: IData) => item._checked),
      });
      return data;
    });

    return {
      c,
      ns,
      columns,
      tableData,
      onDbRowClick,
      onUIRowClick,
      onUIDbRowClick,
      onSelectionChange,
      onSortChange,
      onPageChange,
      onPageSizeChange,
      onPageReset,
      tableHeight,
      gridRef,
      girdPaginationRef,
      highlight,
      isNotFlex,
      grid,
    };
  },
  render() {
    if (!this.c.complete) {
      return;
    }

    // 绘制作用域插槽
    const columnSlots: IData = {};
    // 表格列自定义
    this.c.model.columns.forEach(column => {
      if (column.source.columnType === 'GROUPGRIDCOLUMN') {
        return;
      }
      const columnName = column.codeName;
      columnSlots[columnName] = ({ row, index }: IData) => {
        const rowController = this.c.rows[index - 1];
        if (row.hiddenRow) {
          return (
            <span style='word-break: break-word;white-space: pre-wrap;'>
              隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列
            </span>
          );
        }
        if (rowController) {
          return h(this.c.providers[columnName].component, {
            props: {
              controller: this.c.columns[columnName],
              row: rowController,
            },
            key: row.srfkey + columnName,
          });
        }
      };
    });

    return (
      <control-layout modelData={this.c.model}>
        <div
          ref='gridRef'
          class={[
            this.ns.b(),
            this.ns.is('show-header', !this.c.model.source.hideHeader),
            this.ns.is('enable-page', this.c.model.source.enablePagingBar),
          ]}
          style={this.isNotFlex ? this.grid?.tableStyle : undefined}
        >
          <i-table
            ref={'grid'}
            height={this.tableHeight}
            class={this.ns.b('content')}
            show-header={!this.c.model.source.hideHeader}
            highlight-row={this.c.singleSelect && this.highlight}
            data={this.tableData}
            columns={this.columns}
            on-on-row-click={this.onUIRowClick}
            on-on-row-dblclick={this.onUIDbRowClick}
            on-on-selection-change={this.onSelectionChange}
            on-on-sort-change={this.onSortChange}
            row-class-name={(row: IData) => (row.hiddenRow ? 'hidden-row' : '')}
            span-method={this.c.spanMethod.bind(this.c)}
            scopedSlots={columnSlots}
          ></i-table>
          {this.c.model.source.enablePagingBar && (
            <AppGridPagination
              ref='girdPaginationRef'
              total={this.c.total}
              curPage={this.c.curPage}
              size={this.c.size}
              on-change={this.onPageChange}
              on-page-size-change={this.onPageSizeChange}
              on-page-reset={this.onPageReset}
            ></AppGridPagination>
          )}
        </div>
      </control-layout>
    );
  },
});
