// @vitest-environment jsdom
/**
 * Hook test for useIsMobile — initial match from matchMedia, reaction to a
 * media-query change event, correct query string from the breakpoint, and the
 * no-matchMedia fallback (returns false).
 */
import '../test/dom-setup';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { renderHook, act } from '@testing-library/react';
import { useIsMobile } from './useIsMobile';

interface FakeMql {
  matches: boolean;
  media: string;
  listeners: Set<() => void>;
  addEventListener: (t: string, cb: () => void) => void;
  removeEventListener: (t: string, cb: () => void) => void;
}

let lastQuery = '';
let mql: FakeMql;

function installMatchMedia(initialMatches: boolean) {
  mql = {
    matches: initialMatches,
    media: '',
    listeners: new Set(),
    addEventListener: (_t, cb) => mql.listeners.add(cb),
    removeEventListener: (_t, cb) => mql.listeners.delete(cb),
  };
  vi.stubGlobal('matchMedia', (q: string) => {
    lastQuery = q;
    mql.media = q;
    return mql as unknown as MediaQueryList;
  });
}

function fireChange(next: boolean) {
  mql.matches = next;
  mql.listeners.forEach((cb) => cb());
}

beforeEach(() => {
  lastQuery = '';
});
afterEach(() => {
  vi.unstubAllGlobals();
});

describe('useIsMobile', () => {
  it('reflects the initial matchMedia result', () => {
    installMatchMedia(true);
    const { result } = renderHook(() => useIsMobile());
    expect(result.current).toBe(true);
  });

  it('builds the query from the breakpoint (default 768px → max-width 767.98px)', () => {
    installMatchMedia(false);
    renderHook(() => useIsMobile());
    expect(lastQuery).toBe('(max-width: 767.98px)');
  });

  it('uses a custom breakpoint', () => {
    installMatchMedia(false);
    renderHook(() => useIsMobile(1024));
    expect(lastQuery).toBe('(max-width: 1023.98px)');
  });

  it('updates when the media query changes', () => {
    installMatchMedia(false);
    const { result } = renderHook(() => useIsMobile());
    expect(result.current).toBe(false);
    act(() => fireChange(true));
    expect(result.current).toBe(true);
  });

  it('returns false when matchMedia is unavailable', () => {
    vi.stubGlobal('matchMedia', undefined);
    const { result } = renderHook(() => useIsMobile());
    expect(result.current).toBe(false);
  });
});
