import { useCallback, useEffect, useRef, useState } from 'react';

import { router } from '@inertiajs/react';

interface UseAdminFiltersOptions<T extends Record<string, string | number | boolean | undefined>> {
  /** The route URL to navigate to when filters change. */
  route: string;
  /** The initial filter values from the server. */
  filters: T;
  /** Debounce delay in ms for search input (default: 300). */
  debounce?: number;
  /** Inertia router options. */
  routerOptions?: { preserveScroll?: boolean };
  /**
   * localStorage key for persisting filters across page navigations.
   * Defaults to the route path (auto-persist). Pass null to disable.
   */
  persistKey?: string | null;
}

interface UseAdminFiltersReturn<T extends Record<string, string | number | boolean | undefined>> {
  /** Current search input value (local state, debounced before navigation). */
  search: string;
  /** Update the search input — triggers debounced navigation. */
  setSearch: (value: string) => void;
  /** Update one or more filter values — triggers immediate navigation. */
  updateFilter: (updates: Partial<T>) => void;
  /** Toggle sort column — flips direction if already sorted by that column. */
  handleSort: (column: string) => void;
  /** Navigate to a specific page number. */
  handlePage: (page: number) => void;
  /** Clear all filters and navigate. */
  clearFilters: () => void;
}

/**
 * Shared hook for admin list pages that need debounced search,
 * select filters, sortable columns, and pagination.
 *
 * Eliminates the repeated useState/useRef/setTimeout/router.get pattern
 * across Users, Subscriptions, and Audit Logs pages.
 */
export function useAdminFilters<T extends Record<string, string | number | boolean | undefined>>({
  route,
  filters,
  debounce = 300,
  routerOptions,
  persistKey,
}: UseAdminFiltersOptions<T>): UseAdminFiltersReturn<T> {
  // Compute storage key: explicit value, route-based default, or null to disable.
  const storageKey = persistKey === null ? null : (persistKey ?? `admin-filters:${route}`);

  const [search, setSearchState] = useState(String(filters.search ?? ''));
  const searchTimeout = useRef<ReturnType<typeof setTimeout>>();
  const filtersRef = useRef(filters);
  filtersRef.current = filters;

  useEffect(() => {
    return () => clearTimeout(searchTimeout.current);
  }, []);

  // On mount: if URL has no active filters, restore persisted filters from localStorage.
  useEffect(() => {
    if (!storageKey) return;
    const hasActiveFilters = Object.values(filtersRef.current).some(
      (v) => v !== undefined && v !== '' && v !== null,
    );
    if (hasActiveFilters) return;
    try {
      const saved = localStorage.getItem(storageKey);
      if (!saved) return;
      const parsed = JSON.parse(saved) as Record<string, string | number | boolean | undefined>;
      const hasSaved = Object.values(parsed).some((v) => v !== undefined && v !== '');
      if (!hasSaved) return;
      router.get(route, parsed as Record<string, string | number | boolean | null | undefined>, {
        preserveState: true,
        replace: true,
        ...routerOptions,
      });
    } catch {
      localStorage.removeItem(storageKey);
    }
    // Intentionally run once on mount — restoring saved state.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const navigate = useCallback(
    (params: Record<string, string | number | boolean | undefined>) => {
      if (storageKey) {
        const hasActive = Object.values(params).some((v) => v !== undefined && v !== '');
        if (hasActive) {
          try {
            localStorage.setItem(storageKey, JSON.stringify(params));
          } catch {
            // Storage quota exceeded or unavailable — skip persistence.
          }
        } else {
          localStorage.removeItem(storageKey);
        }
      }
      router.get(route, params as Record<string, string | number | boolean | null | undefined>, {
        preserveState: true,
        replace: true,
        ...routerOptions,
      });
    },
    [route, routerOptions, storageKey],
  );

  const setSearch = useCallback(
    (value: string) => {
      setSearchState(value);
      clearTimeout(searchTimeout.current);
      searchTimeout.current = setTimeout(() => {
        navigate({ ...filtersRef.current, search: value || undefined });
      }, debounce);
    },
    [navigate, debounce],
  );

  const updateFilter = useCallback(
    (updates: Partial<T>) => {
      navigate({ ...filtersRef.current, ...updates });
    },
    [navigate],
  );

  const handleSort = useCallback(
    (column: string) => {
      const current = filtersRef.current as Record<string, string | number | boolean | undefined>;
      const newDir = current.sort === column && current.dir === 'asc' ? 'desc' : 'asc';
      navigate({ ...filtersRef.current, sort: column, dir: newDir });
    },
    [navigate],
  );

  const handlePage = useCallback(
    (page: number) => {
      navigate({ ...filtersRef.current, page });
    },
    [navigate],
  );

  const clearFilters = useCallback(() => {
    setSearchState('');
    if (storageKey) localStorage.removeItem(storageKey);
    navigate({});
  }, [navigate, storageKey]);

  return { search, setSearch, updateFilter, handleSort, handlePage, clearFilters };
}
