import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ChatMessages } from './ChatMessages';

// Mock des services
vi.mock('@/services/websocket', () => ({
  useWebSocket: () => ({
    sendMessage: vi.fn(),
    isConnected: true,
  }),
}));

vi.mock('@/stores/chat', () => ({
  useChatStore: () => ({
    messages: [
      {
        id: '1',
        content: 'Hello, world!',
        sender: { id: '1', username: 'user1' },
        timestamp: '2024-01-01T10:00:00Z',
        type: 'text',
      },
      {
        id: '2',
        content: 'How are you?',
        sender: { id: '2', username: 'user2' },
        timestamp: '2024-01-01T10:01:00Z',
        type: 'text',
      },
    ],
    currentConversation: 'conv-123',
    isLoading: false,
    error: null,
  }),
}));

const createTestQueryClient = () =>
  new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

const TestWrapper = ({ children }: { children: React.ReactNode }) => {
  const queryClient = createTestQueryClient();
  return (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
};

describe('ChatMessages Component', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders messages correctly', () => {
    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    expect(screen.getByText('Hello, world!')).toBeInTheDocument();
    expect(screen.getByText('How are you?')).toBeInTheDocument();
    expect(screen.getByText('user1')).toBeInTheDocument();
    expect(screen.getByText('user2')).toBeInTheDocument();
  });

  it('displays message timestamps', () => {
    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    // Vérifier que les timestamps sont affichés (format peut varier)
    expect(screen.getByText(/10:00/)).toBeInTheDocument();
    expect(screen.getByText(/10:01/)).toBeInTheDocument();
  });

  it('shows loading state when messages are loading', () => {
    vi.mocked(require('@/stores/chat').useChatStore).mockReturnValue({
      messages: [],
      currentConversation: 'conv-123',
      isLoading: true,
      error: null,
    });

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    expect(screen.getByText(/loading messages/i)).toBeInTheDocument();
  });

  it('shows error state when there is an error', () => {
    vi.mocked(require('@/stores/chat').useChatStore).mockReturnValue({
      messages: [],
      currentConversation: 'conv-123',
      isLoading: false,
      error: 'Failed to load messages',
    });

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    expect(screen.getByText(/failed to load messages/i)).toBeInTheDocument();
  });

  it('shows empty state when no messages', () => {
    vi.mocked(require('@/stores/chat').useChatStore).mockReturnValue({
      messages: [],
      currentConversation: 'conv-123',
      isLoading: false,
      error: null,
    });

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    expect(screen.getByText(/no messages yet/i)).toBeInTheDocument();
  });

  it('handles different message types', () => {
    vi.mocked(require('@/stores/chat').useChatStore).mockReturnValue({
      messages: [
        {
          id: '1',
          content: 'Text message',
          sender: { id: '1', username: 'user1' },
          timestamp: '2024-01-01T10:00:00Z',
          type: 'text',
        },
        {
          id: '2',
          content: 'https://example.com',
          sender: { id: '2', username: 'user2' },
          timestamp: '2024-01-01T10:01:00Z',
          type: 'link',
        },
        {
          id: '3',
          content: 'Image message',
          sender: { id: '3', username: 'user3' },
          timestamp: '2024-01-01T10:02:00Z',
          type: 'image',
          imageUrl: 'https://example.com/image.jpg',
        },
      ],
      currentConversation: 'conv-123',
      isLoading: false,
      error: null,
    });

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    expect(screen.getByText('Text message')).toBeInTheDocument();
    expect(screen.getByText('https://example.com')).toBeInTheDocument();
    expect(screen.getByText('Image message')).toBeInTheDocument();
  });

  it('scrolls to bottom when new messages arrive', async () => {
    const scrollIntoViewMock = vi.fn();
    Element.prototype.scrollIntoView = scrollIntoViewMock;

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(scrollIntoViewMock).toHaveBeenCalled();
    });
  });

  it('handles message selection', () => {
    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    const message = screen.getByText('Hello, world!');
    fireEvent.click(message);

    // Vérifier que le message est sélectionné (selon l'implémentation)
    expect(message).toHaveClass('selected');
  });

  it('handles message reactions', () => {
    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    const message = screen.getByText('Hello, world!');
    const reactionButton = message.querySelector(
      '[data-testid="reaction-button"]',
    );

    if (reactionButton) {
      fireEvent.click(reactionButton);
      expect(screen.getByText('👍')).toBeInTheDocument();
    }
  });

  it('handles message editing', async () => {
    const mockUpdateMessage = vi.fn();
    vi.mocked(require('@/stores/chat').useChatStore).mockReturnValue({
      messages: [
        {
          id: '1',
          content: 'Hello, world!',
          sender: { id: '1', username: 'user1' },
          timestamp: '2024-01-01T10:00:00Z',
          type: 'text',
          canEdit: true,
        },
      ],
      currentConversation: 'conv-123',
      isLoading: false,
      error: null,
      updateMessage: mockUpdateMessage,
    });

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    const message = screen.getByText('Hello, world!');
    const editButton = message.querySelector('[data-testid="edit-button"]');

    if (editButton) {
      fireEvent.click(editButton);

      const editInput = screen.getByDisplayValue('Hello, world!');
      fireEvent.change(editInput, {
        target: { value: 'Hello, updated world!' },
      });
      fireEvent.keyDown(editInput, { key: 'Enter' });

      await waitFor(() => {
        expect(mockUpdateMessage).toHaveBeenCalledWith(
          '1',
          'Hello, updated world!',
        );
      });
    }
  });

  it('handles message deletion', async () => {
    const mockDeleteMessage = vi.fn();
    vi.mocked(require('@/stores/chat').useChatStore).mockReturnValue({
      messages: [
        {
          id: '1',
          content: 'Hello, world!',
          sender: { id: '1', username: 'user1' },
          timestamp: '2024-01-01T10:00:00Z',
          type: 'text',
          canDelete: true,
        },
      ],
      currentConversation: 'conv-123',
      isLoading: false,
      error: null,
      deleteMessage: mockDeleteMessage,
    });

    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    const message = screen.getByText('Hello, world!');
    const deleteButton = message.querySelector('[data-testid="delete-button"]');

    if (deleteButton) {
      fireEvent.click(deleteButton);

      const confirmButton = screen.getByText('Delete');
      fireEvent.click(confirmButton);

      await waitFor(() => {
        expect(mockDeleteMessage).toHaveBeenCalledWith('1');
      });
    }
  });

  it('handles keyboard navigation', () => {
    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    const container = screen.getByTestId('chat-messages');
    fireEvent.keyDown(container, { key: 'ArrowUp' });
    fireEvent.keyDown(container, { key: 'ArrowDown' });
    fireEvent.keyDown(container, { key: 'Enter' });
    fireEvent.keyDown(container, { key: 'Escape' });

    // Vérifier que les événements sont gérés correctement
    expect(container).toBeInTheDocument();
  });

  it('handles window resize', () => {
    render(
      <TestWrapper>
        <ChatMessages />
      </TestWrapper>,
    );

    // Simuler un redimensionnement de fenêtre
    fireEvent.resize(window);

    // Vérifier que le composant gère le redimensionnement
    expect(screen.getByTestId('chat-messages')).toBeInTheDocument();
  });
});
