export type PaginationOptions = {
  container: HTMLElement;
  total: number;
  page: number;
  pageSize: number;
  pageSizes?: number[];
  onChange: (page: number, pageSize: number) => Promise<void> | void;
};

function clampPage(page: number, totalPages: number) {
  return Math.min(Math.max(page, 1), totalPages);
}

function pageItems(page: number, totalPages: number) {
  const pages = new Set<number>([1, totalPages, page - 1, page, page + 1]);
  if (page <= 3) {
    pages.add(2);
    pages.add(3);
  }
  if (page >= totalPages - 2) {
    pages.add(totalPages - 1);
    pages.add(totalPages - 2);
  }
  const sorted = [...pages].filter((item) => item >= 1 && item <= totalPages).sort((a, b) => a - b);
  const result: Array<number | "..."> = [];
  for (const item of sorted) {
    const previous = result[result.length - 1];
    if (typeof previous === "number" && item - previous > 1) {
      result.push("...");
    }
    result.push(item);
  }
  return result;
}

export function renderPagination(options: PaginationOptions) {
  const totalPages = Math.max(Math.ceil(options.total / options.pageSize), 1);
  const page = clampPage(options.page, totalPages);
  const pageSizes = options.pageSizes ?? [12, 24, 48, 96];
  const start = options.total === 0 ? 0 : (page - 1) * options.pageSize + 1;
  const end = Math.min(page * options.pageSize, options.total);

  options.container.innerHTML = `
    <div class="pagination-total">共 ${options.total} 条</div>
    <div class="pagination-range">${start}-${end}</div>
    <select class="pagination-size" aria-label="每页条数">
      ${pageSizes.map((size) => `<option value="${size}" ${size === options.pageSize ? "selected" : ""}>${size} 条/页</option>`).join("")}
    </select>
    <button class="pagination-btn" type="button" data-page="${page - 1}" ${page <= 1 ? "disabled" : ""}>上一页</button>
    <div class="pagination-pages">
      ${pageItems(page, totalPages).map((item) => item === "..."
        ? `<span class="pagination-ellipsis">...</span>`
        : `<button class="pagination-btn pagination-page ${item === page ? "is-active" : ""}" type="button" data-page="${item}">${item}</button>`).join("")}
    </div>
    <button class="pagination-btn" type="button" data-page="${page + 1}" ${page >= totalPages ? "disabled" : ""}>下一页</button>
    <label class="pagination-jumper">
      <span>前往</span>
      <input type="number" min="1" max="${totalPages}" value="${page}" />
      <span>页</span>
    </label>
  `;

  options.container.querySelector<HTMLSelectElement>(".pagination-size")?.addEventListener("change", async (event) => {
    const nextPageSize = Number((event.currentTarget as HTMLSelectElement).value);
    await options.onChange(1, nextPageSize);
  });

  options.container.querySelectorAll<HTMLButtonElement>("[data-page]").forEach((button) => {
    button.addEventListener("click", async () => {
      const nextPage = clampPage(Number(button.dataset.page), totalPages);
      if (nextPage === page) return;
      await options.onChange(nextPage, options.pageSize);
    });
  });

  const jumper = options.container.querySelector<HTMLInputElement>(".pagination-jumper input");
  jumper?.addEventListener("keydown", async (event) => {
    if (event.key !== "Enter") return;
    await options.onChange(clampPage(Number(jumper.value || 1), totalPages), options.pageSize);
  });
  jumper?.addEventListener("change", async () => {
    await options.onChange(clampPage(Number(jumper.value || 1), totalPages), options.pageSize);
  });
}
