<template>
  <div>
    <div class="w-grid-content" :style="style" ref="gridContent">
      <GridView
        :theme="theme"
        :columnDefs="getColumnDefs(GridOptions.columnDefs)"
        :rowData="getRowData(Pagination.dataSource)"
        :GridOptions="options"
        :loading="Pagination.loading"
        @loading="onLoading"
      />
    </div>
    <div v-if="ShowPagination">
      <a-divider />
      <Pagination :PageController="Controller" v-bind="paginationOptions" />
    </div>
  </div>
</template>

<script lang="ts">
import { BasesController } from '@mamba/clients';
import type {
  ColDef,
  ColumnApi,
  GridApi,
  GridOptions,
  GridReadyEvent,
  RowDataChangedEvent,
} from 'ag-grid-community';
import lodash from 'lodash';
import { observer } from 'mobx-vue';
import { filter, fromEvent, Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { Component, Inject, Prop, Ref, Vue, Watch } from 'vue-property-decorator';
import defaultOptions, { getColumnDefsAction, getColumnDefsCheckbox } from './defaultOptions';
import framework from './framework';
import loading from './loading.vue';
import Pagination from './pagination.vue';
const Cache = new Map<string, any>();
@observer
@Component({
  components: {
    Pagination,
    // 拆分 包 异步加载
    GridView: () => ({
      component: import('./agGrid.async.vue'),
      loading,
    }),
  },
})
export default class Grid extends Vue {
  @Inject({ from: 'PageController', default: null })
  readonly InjectPageController: BasesController;
  /** 直接传递的 控制器 */
  @Prop({}) readonly PageController: BasesController;
  get Controller() {
    if (this.PageController) {
      return this.PageController;
    }
    return this.InjectPageController;
  }
  /** 分页配置对象 */
  @Prop({ default: () => ({}) }) readonly paginationOptions;
  /** Grid 配置 */
  @Prop({ default: () => ({}) }) readonly GridOptions: GridOptions;
  /** 显示前面的选择框 */
  @Prop({ default: () => true }) readonly CheckboxSelection: boolean;
  /** 显示分页 */
  @Prop({ default: () => true }) readonly ShowPagination: boolean;
  /** 最小高度 */
  @Prop({ default: 500 }) readonly minHeight: number;
  /** 主题 */
  @Prop({ default: 'material' }) readonly theme: 'balham' | 'alpine' | 'material';
  @Ref('gridContent') readonly gridContent: HTMLDivElement;
  style: Partial<CSSStyleDeclaration> = { height: '500px' };
  GridApi: GridApi = null;
  ColumnApi: ColumnApi = null;
  ResizeEvent: Subscription;
  LanguagesEvent: Subscription;
  isAutoSizeColumn = true;
  pageKey = '';
  get Pagination() {
    return this.Controller.Pagination;
  }
  getColumnDefs(columnDefs: Array<ColDef>) {
    return lodash.concat(
      getColumnDefsCheckbox(this.CheckboxSelection, this.theme),
      lodash.filter(columnDefs, (item) => !lodash.eq(lodash.get(item, 'field'), 'RowAction')),
      getColumnDefsAction(columnDefs, this.GridOptions.components),
    );
  }
  getRowData(dataSource) {
    // 行 操作列 用于 触发 RowAction 列 数据变更 列内容触发更新
    if (lodash.has(this.GridOptions.components, 'RowAction')) {
      return lodash.map(dataSource, (item) =>
        lodash.assign({ RowAction: JSON.stringify(item) }, item),
      );
    }
    return dataSource;
  }
  get options(): GridOptions {
    const { components = {}, frameworkComponents = {}, ...gridOptions } = this.GridOptions;
    const options: GridOptions = lodash.assign<GridOptions, GridOptions, GridOptions, GridOptions>(
      {
        frameworkComponents: lodash.assign({}, frameworkComponents, components, framework),
        // 行数据的 id
        getRowId: ({ data }) => lodash.get(data, this.Controller.options.dataKey),
      },
      defaultOptions(this.$i18n as any),
      gridOptions,
      this.GridEvents,
    );
    return options;
  }
  get GridEvents(): GridOptions {
    return {
      onSortChanged: (event) => {
        // const SortModel = lodash.head(event.api.getSortModel());
        // // console.log("LENG ~ Grid ~ getGridEvents ~ event", SortModel)
        // const sory = SortModel && SortModel.sort ? { Direction: lodash.capitalize(SortModel.sort), Property: SortModel.colId } : {}
        // this.Pagination.onLoad({ current: 1 })
        lodash.invoke(this.GridOptions, 'onSortChanged', event);
      },
      // 数据选择
      onSelectionChanged: (event) => {
        this.Pagination.onSelectChange(event.api.getSelectedRows());
        lodash.invoke(this.GridOptions, 'onSelectionChanged', event);
      },
      // 初始化完成
      onGridReady: (event: GridReadyEvent) => {
        this.GridApi = event.api;
        this.ColumnApi = event.columnApi;
        event.api.sizeColumnsToFit();
        if (this.Pagination.loading) {
          this.GridApi.showLoadingOverlay();
        }
        lodash.invoke(this.GridOptions, 'onGridReady', event);
        this.onReckon();
      },
      // onBodyScroll: (event) => {
      //   // console.log("LENG ~ extends ~ event", event.api);
      // },
      // 数据更新
      onRowDataChanged: lodash.debounce((event: RowDataChangedEvent) => {
        this.onAutoSizeAction(event, 'onRowDataChanged');
      }, 300),
      // 数据更新
      onRowDataUpdated: lodash.debounce((event: RowDataChangedEvent) => {
        this.onAutoSizeAction(event, 'onRowDataUpdated');
      }, 300),
    };
  }
  get disparity() {
    const height = 90; //{ material: 90, alpine: 90, balham: 60 }[this.theme];
    if (!this.ShowPagination) {
      return height - 50;
    }
    return height;
  }
  /**
   * 调整行 操作 列大小
   * @param event
   * @param path
   */
  onAutoSizeAction(event: RowDataChangedEvent, path) {
    if (this.isAutoSizeColumn && this.Pagination.dataSource.length > 0) {
      event.columnApi.autoSizeColumn('RowAction');
      // event.api.sizeColumnsToFit();
      this.isAutoSizeColumn = false;
    }
    lodash.invoke(this.GridOptions, path, event);
  }
  /**
   * 获取距离顶部高度
   * @param element
   * @param offsetTop
   */
  getOffsetTop(element: HTMLElement, offsetTop: number = 0) {
    if (element.offsetParent === document.body) {
      return lodash.sum([element.offsetTop, offsetTop]);
    }
    return this.getOffsetTop(
      element.offsetParent as HTMLElement,
      lodash.sum([element.offsetTop, offsetTop]),
    );
  }
  /**
   * 计算 表格高度
   */
  onReckon() {
    try {
      if (
        lodash.includes(
          ['autoHeight', 'print'],
          lodash.defaultTo(this.GridOptions.domLayout, 'autoHeight'),
        )
      ) {
        this.style = {};
        return;
      }
      let height = 500;
      height = window.innerHeight - this.getOffsetTop(this.gridContent) - this.disparity;
      this.style.height = lodash.max([height, this.minHeight]) + 'px';
      if (lodash.get(this, 'AppConfig.userAgent.isMobile')) {
        this.style.height = '70vh';
      }
      Cache.set(this.pageKey, this.style.height);
      this.$nextTick(() => {
        this.GridApi?.sizeColumnsToFit();
        this.ColumnApi?.autoSizeColumn('RowAction');
      });
    } catch (error) {
      console.error('LENG ~ Grid', error);
    }
  }
  // @Watch("Pagination.loading")
  onLoading(val, old) {
    if (this.GridApi) {
      if (val) {
        this.GridApi.showLoadingOverlay();
      } else {
        this.GridApi.hideOverlay();
      }
    }
  }
  @Watch('$route.path')
  onRoute(val, old) {
    if (lodash.eq(val, this.pageKey)) {
      // this.autoSizeColumn()
    }
  }
  // autoSizeColumn = lodash.debounce(() => {
  //   this.onReckon()
  //   this.GridApi?.sizeColumnsToFit();
  //   this.ColumnApi?.autoSizeColumn("RowAction");
  // }, 300)
  created() {
    this.pageKey = this.$route.path;
    if (Cache.has(this.pageKey)) {
      this.style.height = Cache.get(this.pageKey);
    }
  }
  mounted() {
    this.$nextTick(() => this.onReckon());
    this.ResizeEvent = fromEvent(window, 'resize')
      .pipe(
        debounceTime(200),
        // 元素是否在 dom 树中
        filter(() => this.gridContent?.isConnected),
      )
      .subscribe(this.onReckon);
    // this.LanguagesEvent = fromEvent(window, "languages")
    //   .pipe(debounceTime(200))
    //   .subscribe(obx => {
    //     this.ColumnApi?.autoSizeColumn("RowAction");
    //   })
  }
  beforeDestroy() {
    this.ResizeEvent && this.ResizeEvent.unsubscribe();
    this.ResizeEvent = undefined;
  }
}
</script>
<style lang="less">
@import 'ag-grid-community/dist/styles/ag-grid.css';
// @import "ag-grid-community/dist/styles/ag-theme-alpine.css";
// @import "ag-grid-community/dist/styles/ag-theme-balham.css";
@import 'ag-grid-community/dist/styles/ag-theme-material.css';

// 主题定制 https://www.ag-grid.com/vue-grid/themes-customising/
.ag-grid-card {
  // --ag-background-color: @primary-color
  .w-row-action.ag-cell {
    padding-right: 5px;
  }
  &.ag-theme-balham,
  &.ag-theme-material,
  &.ag-theme-alpine {
    transition: height 0.2s;
    // min-height: 350px;

    .ag-checkbox-input-wrapper.ag-checked::after {
      color: @primary-color;
    }

    .ag-rtl .ag-side-bar-left .ag-selected .ag-side-button-button,
    .ag-ltr .ag-side-bar-right .ag-selected .ag-side-button-button,
    .ag-tab-selected {
      border-color: @primary-color;
    }
  }
  .ag-center-cols-container {
    min-width: 100%;
  }
}

.w-grid-content {
  // height: 500px;
  // transition: all 0.2s;
}
</style>
