import { ChevronLeft, ChevronRight } from "lucide-react";
import Link from "next/link";

import { cn } from "@/lib/utils";

/**
 * Numbered pagination built from real `<a>` elements.
 *
 * Because the current filter set is preserved in every href, pagination also
 * behaves correctly with JavaScript disabled and is crawlable by search
 * engines. `rel="prev"/"next"` is emitted for good measure.
 */
export function Pagination({
  page,
  totalPages,
  basePath,
  query,
}: {
  page: number;
  totalPages: number;
  basePath: string;
  /** Current query parameters, minus `page`. */
  query: Record<string, string | undefined>;
}) {
  if (totalPages <= 1) return null;

  const href = (target: number) => {
    const params = new URLSearchParams();
    for (const [key, value] of Object.entries(query)) {
      if (value) params.set(key, value);
    }
    if (target > 1) params.set("page", String(target));
    const qs = params.toString();
    return qs ? `${basePath}?${qs}` : basePath;
  };

  const pages = pageWindow(page, totalPages);
  const prev = page > 1 ? page - 1 : null;
  const next = page < totalPages ? page + 1 : null;

  return (
    <nav
      aria-label="Pagination"
      rel={next ? "next" : undefined}
      className="mt-12 flex flex-wrap items-center justify-center gap-1.5"
    >
      {prev ? (
        <Link
          href={href(prev)}
          rel="prev"
          aria-label="Previous page"
          className="grid size-9 place-items-center rounded-full border border-line text-ink-soft transition-colors hover:border-white/30 hover:text-ink"
        >
          <ChevronLeft className="size-4" />
        </Link>
      ) : (
        <span
          aria-hidden
          className="grid size-9 place-items-center rounded-full border border-line text-ink-faint opacity-40"
        >
          <ChevronLeft className="size-4" />
        </span>
      )}

      {pages.map((entry, i) =>
        entry === null ? (
          <span key={`gap-${i}`} aria-hidden className="px-1 text-ink-faint">
            …
          </span>
        ) : (
          <Link
            key={entry}
            href={href(entry)}
            aria-current={entry === page ? "page" : undefined}
            aria-label={`Page ${entry}`}
            className={cn(
              "grid size-9 place-items-center rounded-full text-[13px] font-semibold transition-colors",
              entry === page
                ? "bg-white text-black"
                : "border border-line text-ink-soft hover:border-white/30 hover:text-ink",
            )}
          >
            {entry}
          </Link>
        ),
      )}

      {next ? (
        <Link
          href={href(next)}
          rel="next"
          aria-label="Next page"
          className="grid size-9 place-items-center rounded-full border border-line text-ink-soft transition-colors hover:border-white/30 hover:text-ink"
        >
          <ChevronRight className="size-4" />
        </Link>
      ) : (
        <span
          aria-hidden
          className="grid size-9 place-items-center rounded-full border border-line text-ink-faint opacity-40"
        >
          <ChevronRight className="size-4" />
        </span>
      )}
    </nav>
  );
}

/**
 * 1 … 4 5 [6] 7 8 … 42
 * Always shows first and last page plus a two-page window around the current one.
 */
function pageWindow(page: number, totalPages: number): (number | null)[] {
  const window = 2;
  const pages = new Set<number>([1, totalPages]);

  for (let p = page - window; p <= page + window; p += 1) {
    if (p >= 1 && p <= totalPages) pages.add(p);
  }

  const sorted = [...pages].sort((a, b) => a - b);
  const out: (number | null)[] = [];

  sorted.forEach((value, i) => {
    if (i > 0 && value - (sorted[i - 1] as number) > 1) out.push(null);
    out.push(value);
  });

  return out;
}
