import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ChatWindow } from '@/components/ai/ChatWindow';

const mockMessages = [
  { id: 'm1', session_id: 's1', role: 'user', content: 'Hello AI', tokens: 10, model_used: '' },
  { id: 'm2', session_id: 's1', role: 'assistant', content: 'Hello User', tokens: 10, model_used: 'gpt-4' },
];

const fetchMessagesMock = vi.fn();
const fetchAttachmentsMock = vi.fn();
const streamChatMock = vi.fn();
const uploadAttachmentMock = vi.fn();

vi.mock('@/api/ai', () => ({
  fetchMessages: (...args: any[]) => fetchMessagesMock(...args),
  fetchAttachments: (...args: any[]) => fetchAttachmentsMock(...args),
  streamChat: (...args: any[]) => streamChatMock(...args),
  uploadAttachment: (...args: any[]) => uploadAttachmentMock(...args),
  getAttachmentDownloadUrl: (id: string) => `/api/v1/ai/attachments/${id}/download`,
}));

vi.mock('react-markdown', () => ({
  default: ({ children }: { children: string }) => <div>{children}</div>,
}));

vi.mock('remark-gfm', () => ({
  default: () => ({}),
}));

beforeEach(() => {
  vi.clearAllMocks();
  fetchMessagesMock.mockResolvedValue(mockMessages);
  fetchAttachmentsMock.mockResolvedValue([]);
  streamChatMock.mockReturnValue({
    async *[Symbol.asyncIterator]() {
      yield { type: 'token', content: 'Hi' };
      yield { type: 'done' };
    },
  });
});

describe('ChatWindow', () => {
  it('renders chat window with messages', async () => {
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByText('Hello AI')).toBeInTheDocument();
      expect(screen.getByText('Hello User')).toBeInTheDocument();
    });
  });

  it('renders textarea input for message', async () => {
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByPlaceholderText('Nachricht eingeben...')).toBeInTheDocument();
    });
  });

  it('renders send button', async () => {
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByText('Senden')).toBeInTheDocument();
    });
  });

  it('disables send button when input is empty', async () => {
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      const sendBtn = screen.getByText('Senden');
      expect(sendBtn).toBeDisabled();
    });
  });

  it('enables send button when input has text', async () => {
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByPlaceholderText('Nachricht eingeben...')).toBeInTheDocument();
    });
    const input = screen.getByPlaceholderText('Nachricht eingeben...');
    fireEvent.change(input, { target: { value: 'Test message' } });
    expect(screen.getByText('Senden')).not.toBeDisabled();
  });

  it('shows empty state when no messages', async () => {
    fetchMessagesMock.mockResolvedValueOnce([]);
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByText('Starte eine Konversation...')).toBeInTheDocument();
    });
  });

  it('displays error when fetchMessages fails', async () => {
    fetchMessagesMock.mockRejectedValueOnce(new Error('Load failed'));
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByText('Load failed')).toBeInTheDocument();
    });
  });

  it('sends message on button click', async () => {
    render(<ChatWindow sessionId="s1" />);
    await waitFor(() => {
      expect(screen.getByPlaceholderText('Nachricht eingeben...')).toBeInTheDocument();
    });
    const input = screen.getByPlaceholderText('Nachricht eingeben...');
    fireEvent.change(input, { target: { value: 'Test message' } });
    fireEvent.click(screen.getByText('Senden'));
    await waitFor(() => {
      expect(streamChatMock).toHaveBeenCalledWith('s1', 'Test message', undefined);
    });
  });
});
