import {
  TableColumnData as BaseColumn,
  TableData as BaseData,
  Table as BaseTable,
  Message,
} from "@arco-design/web-vue";
import { merge } from "lodash-es";
import { PropType, computed, defineComponent, reactive, ref, watch } from "vue";
import { Form, FormInstance, FormModal, FormModalInstance, FormModalProps, FormProps } from "../form";
import { config } from "./table.config";

type DataFn = (search: Record<string, any>, paging: { page: number; size: number }) => Promise<any>;

/**
 * 表格组件
 * @see src/components/table/table.tsx
 */
export const Table = defineComponent({
  name: "Table",
  props: {
    /**
     * 表格数据
     * @description 可以是数组或者函数，函数返回值为`{ data: BaseData[], total: number }`类型
     */
    data: {
      type: [Array, Function] as PropType<BaseData[] | DataFn>,
    },
    /**
     * 表格列设置
     */
    columns: {
      type: Array as PropType<BaseColumn[]>,
      default: () => [],
    },
    /**
     * 分页参数配置
     */
    pagination: {
      type: Object as PropType<any>,
      default: () => reactive(config.pagination),
    },
    /**
     * 搜索表单配置
     */
    search: {
      type: Object as PropType<FormProps>,
    },
    /**
     * 新建弹窗配置
     */
    create: {
      type: Object as PropType<FormModalProps>,
    },
    /**
     * 修改弹窗配置
     */
    modify: {
      type: Object as PropType<FormModalProps>,
    },
    /**
     * 详情弹窗配置
     */
    detail: {
      type: Object as PropType<any>,
    },
    /**
     * 传递给 Table 组件的属性
     */
    tableProps: {
      type: Object as PropType<InstanceType<typeof BaseTable>["$props"]>,
    },
  },
  setup(props) {
    const loading = ref(false);
    const tableRef = ref<InstanceType<typeof BaseTable>>()
    const searchRef = ref<FormInstance>();
    const createRef = ref<FormModalInstance>();
    const modifyRef = ref<FormModalInstance>();
    const renderData = ref<BaseData[]>([]);
    const inlined = computed(() => (props.search?.items?.length ?? 0) <= config.searchInlineCount);
    const reloadData = () => loadData({ current: 1, pageSize: 10 });
    const openModifyModal = (data: any) => modifyRef.value?.open(data);

    const loadData = async (pagination: Partial<any> = {}) => {
      const merged = { ...props.pagination, ...pagination };
      const paging = { page: merged.current, size: merged.pageSize };
      const model = searchRef.value?.getModel() ?? {};
      if (Array.isArray(props.data)) {
        const filters = Object.entries(model);
        const data = props.data.filter((item) => {
          return filters.every(([key, value]) => {
            if (typeof value === "string") {
              return item[key].includes(value);
            }
            return item[key] === value;
          });
        });
        renderData.value = data;
        props.pagination.total = renderData.value.length;
        props.pagination.current = 1;
      }
      if (typeof props.data === "function") {
        try {
          loading.value = true;
          const resData = await props.data(model, paging);
          const { data = [], total = 0 } = resData?.data || {};
          renderData.value = data;
          props.pagination.total = total;
          props.pagination.current = paging.page;
        } catch (error) {
          const message = config.getApiErrorMessage(error);
          if (message) {
            Message.error(`提示：${message}`);
          }
        } finally {
          loading.value = false;
        }
      }
    };

    watch(
      () => props.data,
      (data) => {
        if (Array.isArray(data)) {
          renderData.value = data;
          props.pagination.total = data.length;
          props.pagination.current = 1;
        }
      },
      {
        immediate: true,
      }
    );

    onMounted(() => {
      loadData();
    });

    if (props.search) {
      merge(props.search, { formProps: { layout: "inline" } });
    }

    const state = {
      loading,
      inlined,
      tableRef,
      searchRef,
      createRef,
      modifyRef,
      renderData,
      loadData,
      reloadData,
      openModifyModal,
    };

    provide("ref:table", { ...state, ...props });

    return state;
  },
  render() {
    (this.columns as any).instance = this;
    return (
      <div class="table w-full">
        {!this.inlined && (
          <div class="border-b pb-0 border-slate-200 mb-3">
            <Form ref="searchRef" class="!grid grid-cols-4 gap-x-6" {...this.search}></Form>
          </div>
        )}

        <div class={`mb-3 flex toolbar justify-between ${!this.inlined && "mt-2"}`}>
          <div class={`${this.create || this.$slots.action ? null : "!hidden"} flex-1 flex gap-2 `}>
            {this.create && (
              <FormModal {...(this.create as any)} ref="createRef" onSubmited={this.reloadData}></FormModal>
            )}
            {this.modify && (
              <FormModal
                {...(this.modify as any)}
                ref="modifyRef"
                onSubmited={this.reloadData}
                trigger={false}
              ></FormModal>
            )}
            {this.$slots.action?.()}
          </div>
          <div>{this.inlined && <Form ref="searchRef" {...this.search}></Form>}</div>
        </div>

        <BaseTable
          ref="tableRef"
          row-key="id"
          bordered={false}
          {...this.$attrs}
          {...this.tableProps}
          loading={this.loading}
          pagination={this.pagination}
          data={this.renderData}
          columns={this.columns}
          onPageChange={(current: number) => this.loadData({ current })}
        ></BaseTable>
      </div>
    );
  },
});

/**
 * 表格组件实例
 */
export type TableInstance = InstanceType<typeof Table>;

/**
 * 表格组件参数
 */
export type TableProps = TableInstance["$props"];
