import { renderHook, act } from '@testing-library/react';

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

import { useFilterState } from './useFilterState';

vi.mock('@inertiajs/react', () => ({
  router: {
    reload: vi.fn(),
  },
}));

describe('useFilterState', () => {
  beforeEach(() => {
    vi.mocked(router.reload).mockReset();
    vi.useFakeTimers();
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  it('returns initial filters', () => {
    const initial = { search: '', status: 'all' };
    const { result } = renderHook(() => useFilterState(initial));
    expect(result.current.filters).toEqual(initial);
  });

  it('starts with isFiltering false', () => {
    const { result } = renderHook(() => useFilterState({ search: '' }));
    expect(result.current.isFiltering).toBe(false);
  });

  it('updates filter state immediately on setFilter', () => {
    const { result } = renderHook(() => useFilterState({ search: '', status: 'all' }));

    act(() => {
      result.current.setFilter('search', 'hello');
    });

    expect(result.current.filters.search).toBe('hello');
    // status unchanged
    expect(result.current.filters.status).toBe('all');
  });

  it('calls router.reload after debounce delay', () => {
    const { result } = renderHook(() => useFilterState({ search: '' }, 300));

    act(() => {
      result.current.setFilter('search', 'test');
    });

    // Not called yet
    expect(router.reload).not.toHaveBeenCalled();

    act(() => {
      vi.advanceTimersByTime(300);
    });

    expect(router.reload).toHaveBeenCalledWith(
      expect.objectContaining({
        data: { search: 'test' },
        replace: true,
      }),
    );
  });

  it('debounces rapid filter changes — only calls reload once', () => {
    const { result } = renderHook(() => useFilterState({ search: '' }, 300));

    act(() => {
      result.current.setFilter('search', 'a');
      result.current.setFilter('search', 'ab');
      result.current.setFilter('search', 'abc');
    });

    act(() => {
      vi.advanceTimersByTime(300);
    });

    expect(router.reload).toHaveBeenCalledTimes(1);
    expect(router.reload).toHaveBeenCalledWith(
      expect.objectContaining({ data: { search: 'abc' } }),
    );
  });

  it('resets to initial filters and calls router.reload', () => {
    const initial = { search: '', status: 'all' };
    const { result } = renderHook(() => useFilterState(initial, 0));

    act(() => {
      result.current.setFilter('search', 'hello');
      result.current.setFilter('status', 'active');
    });

    act(() => {
      vi.advanceTimersByTime(0);
    });

    act(() => {
      result.current.resetFilters();
    });

    act(() => {
      vi.advanceTimersByTime(0);
    });

    expect(result.current.filters).toEqual(initial);
    // reload called at least once for reset
    expect(router.reload).toHaveBeenCalledWith(expect.objectContaining({ data: initial }));
  });

  it('sets isFiltering to true during pending debounce and false after onFinish', () => {
    let capturedOnFinish: (() => void) | undefined;
    vi.mocked(router.reload).mockImplementation((opts) => {
      capturedOnFinish = (opts as { onFinish?: () => void }).onFinish;
    });

    const { result } = renderHook(() => useFilterState({ search: '' }, 100));

    act(() => {
      result.current.setFilter('search', 'x');
    });

    expect(result.current.isFiltering).toBe(true);

    act(() => {
      vi.advanceTimersByTime(100);
    });

    act(() => {
      capturedOnFinish?.();
    });

    expect(result.current.isFiltering).toBe(false);
  });
});
