"use client";

import { useRouter, useSearchParams, usePathname } from "next/navigation";
import { useCallback, useRef, useTransition } from "react";

// Typed-routes are enabled in next.config.ts; bypass for dynamic URLs.
type PlainRouter = { replace: (url: string, opts?: { scroll?: boolean }) => void };

/**
 * Syncs a filter object with URL search params.
 * T must be a flat record of string | undefined values.
 *
 * - Reads current filter values from URL search params, falling back to `defaults`.
 * - Returns a stable `setFilters` updater that writes to the URL via `router.replace`
 *   (no back-button history entry per keystroke).
 * - Default values are NOT written to the URL, keeping URLs clean and shareable.
 */
export function useUrlFilters<T extends Record<string, string | undefined>>(
  defaults: T,
): [T, (updates: Partial<T>) => void] {
  const searchParams = useSearchParams();
  const router = useRouter() as unknown as PlainRouter;
  const pathname = usePathname();
  const [, startTransition] = useTransition();

  // Stable ref so setFilters doesn't need defaults in its deps array.
  const defaultsRef = useRef(defaults);
  defaultsRef.current = defaults;

  // Read current values from URL, falling back to defaults
  const filters = Object.fromEntries(
    Object.keys(defaults).map((key) => {
      const val = searchParams.get(key);
      return [key, val ?? defaults[key]];
    }),
  ) as T;

  const setFilters = useCallback(
    (updates: Partial<T>) => {
      const params = new URLSearchParams(searchParams.toString());
      const defs = defaultsRef.current;

      for (const [key, value] of Object.entries(updates)) {
        if (value === undefined || value === defs[key as keyof T]) {
          params.delete(key); // Clean URL — don't show default values
        } else {
          params.set(key, String(value));
        }
      }

      startTransition(() => {
        router.replace(`${pathname}?${params.toString()}`, { scroll: false });
      });
    },
    [searchParams, router, pathname],
  );

  return [filters, setFilters];
}
