export const ALLOWED_SORTS = ["relevance", "newest", "price_asc", "price_desc", "popular"] as const;
export type ItemSearchSort = (typeof ALLOWED_SORTS)[number];

export const DEFAULT_PER_PAGE = 24;
export const MAX_PER_PAGE = 60;

export interface ItemSearchParams {
  q: string | null;
  categorySlug: string | null;
  brand: string[];
  size: string[];
  condition: string[];
  colors: string[];
  storeId: string[];
  minPrice: number | null;
  maxPrice: number | null;
  sort: ItemSearchSort;
  page: number;
  perPage: number;
}

function readArray(params: URLSearchParams, key: string): string[] {
  return params.getAll(key).filter((v) => v.length > 0);
}

function readInt(params: URLSearchParams, key: string): number | null {
  const v = params.get(key);
  if (v === null || v === "") return null;
  const n = Number(v);
  return Number.isFinite(n) ? n : null;
}

export function parseItemSearchParams(searchParams: URLSearchParams): ItemSearchParams {
  const q = searchParams.get("q")?.trim() || null;

  const rawSort = searchParams.get("sort");
  const sort: ItemSearchSort = (ALLOWED_SORTS as readonly string[]).includes(rawSort ?? "")
    ? (rawSort as ItemSearchSort)
    : q !== null
      ? "relevance"
      : "newest";

  const page = Math.max(1, readInt(searchParams, "page") ?? 1);
  const perPage = Math.min(MAX_PER_PAGE, Math.max(1, readInt(searchParams, "per_page") ?? DEFAULT_PER_PAGE));

  return {
    q,
    categorySlug: searchParams.get("category_slug")?.trim() || null,
    brand: readArray(searchParams, "brand"),
    size: readArray(searchParams, "size"),
    condition: readArray(searchParams, "condition"),
    colors: readArray(searchParams, "colors"),
    storeId: readArray(searchParams, "store_id"),
    minPrice: readInt(searchParams, "min_price"),
    maxPrice: readInt(searchParams, "max_price"),
    sort,
    page,
    perPage,
  };
}

export function buildItemSearchUrl(
  current: ItemSearchParams,
  patch: Partial<ItemSearchParams>,
  pathname = "/items",
): string {
  const next: ItemSearchParams = { ...current, ...patch };
  // Reset page on any non-page patch so filter changes always land on page 1
  if (!("page" in patch)) {
    next.page = 1;
  }

  const sp = new URLSearchParams();

  if (next.q) sp.set("q", next.q);
  if (next.categorySlug) sp.set("category_slug", next.categorySlug);
  for (const b of next.brand) sp.append("brand", b);
  for (const s of next.size) sp.append("size", s);
  for (const c of next.condition) sp.append("condition", c);
  for (const c of next.colors) sp.append("colors", c);
  for (const s of next.storeId) sp.append("store_id", s);
  if (next.minPrice !== null) sp.set("min_price", String(next.minPrice));
  if (next.maxPrice !== null) sp.set("max_price", String(next.maxPrice));

  // Only include sort if it differs from the implicit default
  const implicitSort: ItemSearchSort = next.q !== null ? "relevance" : "newest";
  if (next.sort !== implicitSort) sp.set("sort", next.sort);

  if (next.page !== 1) sp.set("page", String(next.page));
  if (next.perPage !== DEFAULT_PER_PAGE) sp.set("per_page", String(next.perPage));

  const qs = sp.toString();
  return qs ? `${pathname}?${qs}` : pathname;
}
