<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue';

import { preferences } from '@easyflow/preferences';

import { ElButton, ElEmpty, ElPagination } from 'element-plus';

import { api } from '#/api/request';
import { getEmptyStateImageUrl } from '#/utils/assets';

interface PageDataProps {
  pageUrl: string;
  pageSize?: number;
  pageSizes?: number[];
  extraQueryParams?: Record<string, any>;
  initialPageNumber?: number;
  initialQueryParams?: Record<string, any>;
  requestClient?: any;
}

type PageDataRow = Record<string, any>;
interface PageDataState {
  pageNumber: number;
  pageSize: number;
}

interface PageDataRestoreState extends PageDataState {
  queryParams?: Record<string, any>;
}

interface PageDataReloadOptions {
  silent?: boolean;
}

interface PageDataRequest {
  silent: boolean;
  version: number;
}

const props = withDefaults(defineProps<PageDataProps>(), {
  pageSize: 10,
  pageSizes: () => [10, 20, 50, 100],
  extraQueryParams: () => ({}),
  initialPageNumber: 1,
  initialQueryParams: () => ({}),
  requestClient: () => api,
});
const emit = defineEmits<{
  (e: 'stateChange', state: PageDataState): void;
}>();

// 响应式数据
const pageList = ref<PageDataRow[]>([]);
const loading = ref(false);
const loadError = ref<unknown>();
const queryParams = ref<Record<string, any>>(
  normalizeQueryParams(props.initialQueryParams),
);
let activePageRequest: null | Promise<void> = null;
let pendingPageRequest: null | PageDataRequest = null;
let pageRequestVersion = 0;

const pageInfo = reactive({
  pageNumber: Math.max(1, Math.trunc(props.initialPageNumber)),
  pageSize: props.pageSize,
  total: 0,
});

// 模拟 API 调用 - 这里需要根据你的实际 API 调用方式调整
const doGet = async (params: Record<string, any>) => {
  // 这里替换为你的实际 API 调用
  // 例如：return await api.get(props.pageUrl, { params })
  const response = await props.requestClient.get(`${props.pageUrl}`, {
    params,
  });
  const data = await response.data;
  return { data };
};

const loadPageListOnce = async (request: PageDataRequest) => {
  try {
    const res = await doGet({
      pageNumber: pageInfo.pageNumber,
      pageSize: pageInfo.pageSize,
      ...props.extraQueryParams,
      ...queryParams.value,
    });
    if (request.version === pageRequestVersion) {
      const rawTotal = Number(res.data?.totalRow || 0);
      const total = Number.isFinite(rawTotal) ? Math.max(0, rawTotal) : 0;
      const lastPage = Math.max(1, Math.ceil(total / pageInfo.pageSize));
      pageInfo.total = total;
      if (pageInfo.pageNumber > lastPage) {
        pageInfo.pageNumber = lastPage;
        emitPageState();
        return;
      }
      pageList.value = res.data?.records || [];
    }
  } catch (error) {
    if (request.version === pageRequestVersion) {
      loadError.value = error;
      if (!request.silent || pageList.value.length === 0) {
        pageList.value = [];
        pageInfo.total = 0;
      }
    }
  }
};

const requestPageList = (silent: boolean) => {
  const request: PageDataRequest = {
    silent: silent && pageList.value.length > 0,
    version: ++pageRequestVersion,
  };
  loadError.value = undefined;
  if (!request.silent) {
    loading.value = true;
  }
  if (activePageRequest) {
    pendingPageRequest = pendingPageRequest
      ? {
          silent: pendingPageRequest.silent && request.silent,
          version: request.version,
        }
      : request;
    return activePageRequest;
  }

  const drainPageRequests = async () => {
    let currentRequest: null | PageDataRequest = request;
    while (currentRequest) {
      pendingPageRequest = null;
      await loadPageListOnce(currentRequest);
      currentRequest = pendingPageRequest;
    }
  };
  activePageRequest = drainPageRequests().finally(() => {
    activePageRequest = null;
    loading.value = false;
  });
  return activePageRequest;
};

// 获取页面数据
const getPageList = () => requestPageList(false);

const reload = (options: PageDataReloadOptions = {}) =>
  requestPageList(Boolean(options.silent));

// 分页事件处理
const handleSizeChange = (newSize: number) => {
  pageInfo.pageSize = newSize;
  pageInfo.pageNumber = 1; // 重置到第一页
  emitPageState();
};

const handleCurrentChange = (newPage: number) => {
  pageInfo.pageNumber = newPage;
  emitPageState();
};

const getPageState = (): PageDataState => ({
  pageNumber: pageInfo.pageNumber,
  pageSize: pageInfo.pageSize,
});

function normalizeQueryParams(value: Record<string, any> = {}) {
  return Object.fromEntries(
    Object.entries(value).filter(([, item]) => item !== undefined),
  );
}

function queryParamsEqual(
  left: Record<string, any>,
  right: Record<string, any>,
) {
  const leftKeys = Object.keys(left);
  const rightKeys = Object.keys(right);
  return (
    leftKeys.length === rightKeys.length &&
    leftKeys.every((key) => Object.is(left[key], right[key]))
  );
}

const emitPageState = () => {
  emit('stateChange', getPageState());
};

const patchRowById = (
  id: number | string,
  patch: Record<string, any>,
): boolean => {
  const rowIndex = pageList.value.findIndex(
    (item) => String(item?.id ?? '') === String(id ?? ''),
  );
  if (rowIndex === -1) {
    return false;
  }
  const nextPageList = [...pageList.value];
  nextPageList[rowIndex] = {
    ...nextPageList[rowIndex],
    ...patch,
  };
  pageList.value = nextPageList;
  return true;
};

// 暴露给父组件的方法 (替代 useImperativeHandle)
const setQuery = (newQueryParams: Record<string, any>) => {
  pageInfo.pageNumber = 1;
  pageInfo.pageSize = props.pageSize;
  queryParams.value = normalizeQueryParams(newQueryParams);
  emitPageState();
};

/**
 * 将已挂载的列表恢复为路由指定状态，同一状态不会重复发起请求。
 */
const restoreState = (state: PageDataRestoreState) => {
  const nextPageNumber = Math.max(1, Math.trunc(state.pageNumber));
  const nextPageSize = Math.max(1, Math.trunc(state.pageSize));
  const nextQueryParams = normalizeQueryParams(state.queryParams);
  if (
    pageInfo.pageNumber === nextPageNumber &&
    pageInfo.pageSize === nextPageSize &&
    queryParamsEqual(queryParams.value, nextQueryParams)
  ) {
    return false;
  }
  pageInfo.pageNumber = nextPageNumber;
  pageInfo.pageSize = nextPageSize;
  queryParams.value = nextQueryParams;
  emitPageState();
  return true;
};

// 暴露方法给父组件
defineExpose({
  getPageState,
  reload,
  patchRowById,
  restoreState,
  setQuery,
});

// 监听器
watch(
  [() => pageInfo.pageNumber, () => pageInfo.pageSize, () => queryParams.value],
  () => {
    getPageList();
  },
  { deep: true },
);

// 生命周期
onMounted(() => {
  emitPageState();
  getPageList();
});
</script>

<template>
  <div class="page-data-container" v-loading="loading">
    <template v-if="pageList.length > 0">
      <div class="page-data-container__body">
        <slot :page-list="pageList"></slot>
      </div>
      <div
        v-if="pageInfo.total > pageInfo.pageSize"
        class="page-data-container__pagination mx-auto mt-6 w-fit"
      >
        <ElPagination
          v-model:current-page="pageInfo.pageNumber"
          v-model:page-size="pageInfo.pageSize"
          :total="pageInfo.total"
          :page-sizes="pageSizes"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </template>
    <slot
      v-else-if="loadError"
      name="error"
      :error="loadError"
      :retry="getPageList"
    >
      <ElEmpty description="数据加载失败，请重试">
        <ElButton type="primary" @click="getPageList">重新加载</ElButton>
      </ElEmpty>
    </slot>
    <slot v-else name="empty">
      <ElEmpty :image="getEmptyStateImageUrl(preferences.theme.mode)" />
    </slot>
  </div>
</template>

<style scoped>
.page-data-container {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  padding: 18px 20px;
}

.page-data-container__body {
  flex: 1;
  min-height: 0;
}

.page-data-container__pagination {
  flex-shrink: 0;
  padding-top: 4px;
}

@media (max-width: 768px) {
  .page-data-container {
    padding: 14px 14px 12px;
  }
}
</style>
