import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { renderHook } from '@testing-library/react';
import { useOnlineStatus } from './useOnlineStatus';

describe('useOnlineStatus', () => {
  beforeEach(() => {
    // Mock navigator.onLine
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: true,
    });
  });

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

  it('should return true when navigator.onLine is true', () => {
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: true,
    });

    const { result } = renderHook(() => useOnlineStatus());

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

  it('should return false when navigator.onLine is false', () => {
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: false,
    });

    const { result } = renderHook(() => useOnlineStatus());

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

  it('should update when online event fires', async () => {
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: false,
    });

    const { result, waitForNextUpdate } = renderHook(() => useOnlineStatus());

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

    // Simulate online event
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: true,
    });

    window.dispatchEvent(new Event('online'));

    // Wait for state update
    await waitForNextUpdate();

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

  it('should update when offline event fires', async () => {
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: true,
    });

    const { result, waitForNextUpdate } = renderHook(() => useOnlineStatus());

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

    // Simulate offline event
    Object.defineProperty(navigator, 'onLine', {
      writable: true,
      configurable: true,
      value: false,
    });

    window.dispatchEvent(new Event('offline'));

    // Wait for state update
    await waitForNextUpdate();

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

  it('should return true when navigator is undefined', () => {
    const originalNavigator = global.navigator;
    // @ts-ignore
    delete global.navigator;

    const { result } = renderHook(() => useOnlineStatus());

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

    global.navigator = originalNavigator;
  });

  it('should clean up event listeners on unmount', () => {
    const removeEventListenerSpy = vi.spyOn(window, 'removeEventListener');

    const { unmount } = renderHook(() => useOnlineStatus());

    unmount();

    expect(removeEventListenerSpy).toHaveBeenCalledWith(
      'online',
      expect.any(Function),
    );
    expect(removeEventListenerSpy).toHaveBeenCalledWith(
      'offline',
      expect.any(Function),
    );

    removeEventListenerSpy.mockRestore();
  });
});
