// src/hooks/useModal.test.ts
import { renderHook, act } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import React from 'react';
import { useModal } from './useModal';
import { ModalProvider } from '../providers/ModalProvider';

// Create a wrapper component that includes the ModalProvider.
// This is necessary because the useModal hook depends on the context provided by ModalProvider.
const wrapper = ({ children }: { children: React.ReactNode }) => (
  <ModalProvider>{children}</ModalProvider>
);

describe('useModal Hook with ModalProvider', () => {
  // Suppress console.error for the expected error test
  beforeEach(() => {
    vi.spyOn(console, 'error').mockImplementation(() => {});
  });

  it('should throw an error when used outside of a ModalProvider', () => {
    // Render the hook without the wrapper to test the error boundary.
    let error: Error | undefined;
    try {
      renderHook(() => useModal());
    } catch (e) {
      error = e as Error;
    }
    // The hook throws an error, which is caught by the try/catch block.
    // We check the error message directly.
    // Note: renderHook's result.error is for async errors, not initial render errors.
    expect(error?.message).toEqual('useModal must be used within a ModalProvider');
  });

  it('should initialize with all modals closed', () => {
    const { result } = renderHook(() => useModal(), { wrapper });

    expect(result.current.isModalOpen('profile')).toBe(false);
    expect(result.current.isModalOpen('voiceAssistant')).toBe(false);
    expect(result.current.isModalOpen('whatsNew')).toBe(false);
    expect(result.current.isModalOpen('correctionTool')).toBe(false);
  });

  it('should open a specific modal when openModal is called', () => {
    const { result } = renderHook(() => useModal(), { wrapper });

    act(() => {
      result.current.openModal('profile');
    });

    expect(result.current.isModalOpen('profile')).toBe(true);
    // Ensure other modals remain closed
    expect(result.current.isModalOpen('whatsNew')).toBe(false);
  });

  it('should close a specific modal when closeModal is called', () => {
    const { result } = renderHook(() => useModal(), { wrapper });

    // First, open a modal
    act(() => {
      result.current.openModal('voiceAssistant');
    });
    expect(result.current.isModalOpen('voiceAssistant')).toBe(true);

    // Then, close it
    act(() => {
      result.current.closeModal('voiceAssistant');
    });

    expect(result.current.isModalOpen('voiceAssistant')).toBe(false);
  });

  it('should manage the state of multiple modals independently', () => {
    const { result } = renderHook(() => useModal(), { wrapper });

    act(() => {
      result.current.openModal('profile');
      result.current.openModal('whatsNew');
    });

    expect(result.current.isModalOpen('profile')).toBe(true);
    expect(result.current.isModalOpen('whatsNew')).toBe(true);
    expect(result.current.isModalOpen('voiceAssistant')).toBe(false);

    act(() => {
      result.current.closeModal('profile');
    });

    expect(result.current.isModalOpen('profile')).toBe(false);
    expect(result.current.isModalOpen('whatsNew')).toBe(true);
  });

  it('should maintain stable function references across re-renders due to useCallback', () => {
    const { result, rerender } = renderHook(() => useModal(), { wrapper });

    const initialOpenModal = result.current.openModal;
    const initialCloseModal = result.current.closeModal;
    const initialIsModalOpen = result.current.isModalOpen;

    rerender();

    expect(result.current.openModal).toBe(initialOpenModal);
    expect(result.current.closeModal).toBe(initialCloseModal);
    expect(result.current.isModalOpen).toBe(initialIsModalOpen);
  });
});