import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { ChatInterface } from '@/components/copilot/ChatInterface';
import { MessageList } from '@/components/copilot/MessageList';
import { ChatInput } from '@/components/copilot/ChatInput';
import { ActionPreview } from '@/components/copilot/ActionPreview';
import { ChatHistory } from '@/components/copilot/ChatHistory';

vi.mock('@/lib/copilot', () => ({
  sendChatMessage: vi.fn(),
  executeAction: vi.fn(),
  getChatHistory: vi.fn(),
  sendVoiceMessage: vi.fn(),
  fileToBase64: vi.fn(),
}));

import { sendChatMessage, executeAction, getChatHistory } from '@/lib/copilot';
import type { ActionItem, ChatMessage } from '@/lib/copilot';

describe('ChatInput', () => {
  it('renders input and send button', () => {
    render(<ChatInput onSend={vi.fn()} />);
    expect(screen.getByTestId('chat-input')).toBeInTheDocument();
    expect(screen.getByTestId('send-button')).toBeInTheDocument();
  });

  it('calls onSend when send button clicked', () => {
    const onSend = vi.fn();
    render(<ChatInput onSend={onSend} />);
    const input = screen.getByTestId('chat-input') as HTMLTextAreaElement;
    fireEvent.change(input, { target: { value: 'Test message' } });
    fireEvent.click(screen.getByTestId('send-button'));
    expect(onSend).toHaveBeenCalledWith('Test message');
  });

  it('clears input after send', () => {
    render(<ChatInput onSend={vi.fn()} />);
    const input = screen.getByTestId('chat-input') as HTMLTextAreaElement;
    fireEvent.change(input, { target: { value: 'Test' } });
    fireEvent.click(screen.getByTestId('send-button'));
    expect(input.value).toBe('');
  });

  it('does not send empty messages', () => {
    const onSend = vi.fn();
    render(<ChatInput onSend={onSend} />);
    fireEvent.click(screen.getByTestId('send-button'));
    expect(onSend).not.toHaveBeenCalled();
  });

  it('is disabled when disabled prop is true', () => {
    render(<ChatInput onSend={vi.fn()} disabled />);
    expect(screen.getByTestId('send-button')).toBeDisabled();
  });
});

describe('MessageList', () => {
  it('shows placeholder when no messages', () => {
    render(<MessageList messages={[]} />);
    expect(screen.getByText('Starte eine Konversation mit dem KI-Copilot...')).toBeInTheDocument();
  });

  it('renders user and assistant messages', () => {
    const messages: ChatMessage[] = [
      { id: '1', session_id: 's1', role: 'user', content: 'Hallo', created_at: '2025-01-01T00:00:00Z' },
      { id: '2', session_id: 's1', role: 'assistant', content: 'Hi there!', created_at: '2025-01-01T00:00:01Z' },
    ];
    render(<MessageList messages={messages} />);
    expect(screen.getByText('Hallo')).toBeInTheDocument();
    expect(screen.getByText('Hi there!')).toBeInTheDocument();
  });

  it('shows loading indicator', () => {
    render(<MessageList messages={[]} loading />);
    expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  });

  it('displays action proposals in assistant messages', () => {
    const messages: ChatMessage[] = [
      {
        id: '1', session_id: 's1', role: 'assistant', content: 'Ich suche LKWs.',
        actions: [{ type: 'search_vehicles', params: { type: 'lkw' } }],
        created_at: '2025-01-01T00:00:00Z',
      },
    ];
    render(<MessageList messages={messages} />);
    expect(screen.getByText('Vorgeschlagene Aktionen:')).toBeInTheDocument();
    expect(screen.getByText('search_vehicles')).toBeInTheDocument();
  });
});

describe('ActionPreview', () => {
  const mockActions: ActionItem[] = [
    { type: 'search_vehicles', params: { type: 'lkw' } },
  ];

  it('renders action preview with confirm and dismiss buttons', () => {
    render(<ActionPreview actions={mockActions} onConfirm={vi.fn()} onDismiss={vi.fn()} />);
    expect(screen.getByTestId('action-preview')).toBeInTheDocument();
    expect(screen.getByTestId('confirm-action-0')).toBeInTheDocument();
    expect(screen.getByTestId('dismiss-action-0')).toBeInTheDocument();
  });

  it('calls onConfirm when confirm button clicked', () => {
    const onConfirm = vi.fn();
    render(<ActionPreview actions={mockActions} onConfirm={onConfirm} onDismiss={vi.fn()} />);
    fireEvent.click(screen.getByTestId('confirm-action-0'));
    expect(onConfirm).toHaveBeenCalledWith(mockActions[0]);
  });

  it('calls onDismiss when dismiss button clicked', () => {
    const onDismiss = vi.fn();
    render(<ActionPreview actions={mockActions} onConfirm={vi.fn()} onDismiss={onDismiss} />);
    fireEvent.click(screen.getByTestId('dismiss-action-0'));
    expect(onDismiss).toHaveBeenCalledWith(mockActions[0]);
  });

  it('returns null when no actions', () => {
    const { container } = render(<ActionPreview actions={[]} onConfirm={vi.fn()} onDismiss={vi.fn()} />);
    expect(container.firstChild).toBeNull();
  });

  it('shows action label for known action types', () => {
    render(<ActionPreview actions={mockActions} onConfirm={vi.fn()} onDismiss={vi.fn()} />);
    expect(screen.getByText('Fahrzeuge durchsuchen')).toBeInTheDocument();
  });
});

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

  it('renders history sidebar with title', async () => {
    vi.mocked(getChatHistory).mockResolvedValue({ items: [], total: 0, page: 1, page_size: 100 });
    render(<ChatHistory onSelectSession={vi.fn()} onClose={vi.fn()} />);
    expect(screen.getByText('Konversationen')).toBeInTheDocument();
  });

  it('shows empty state when no sessions', async () => {
    vi.mocked(getChatHistory).mockResolvedValue({ items: [], total: 0, page: 1, page_size: 100 });
    render(<ChatHistory onSelectSession={vi.fn()} onClose={vi.fn()} />);
    await waitFor(() => { expect(screen.getByTestId('history-empty')).toBeInTheDocument(); });
  });

  it('displays sessions grouped by session_id', async () => {
    const messages: ChatMessage[] = [
      { id: '1', session_id: 's1', role: 'user', content: 'Erste Frage', created_at: '2025-01-01T00:00:00Z' },
      { id: '2', session_id: 's1', role: 'assistant', content: 'Antwort', created_at: '2025-01-01T00:00:01Z' },
      { id: '3', session_id: 's2', role: 'user', content: 'Zweite Frage', created_at: '2025-01-02T00:00:00Z' },
    ];
    vi.mocked(getChatHistory).mockResolvedValue({ items: messages, total: 3, page: 1, page_size: 100 });
    render(<ChatHistory onSelectSession={vi.fn()} onClose={vi.fn()} />);
    await waitFor(() => {
      expect(screen.getByText('Erste Frage')).toBeInTheDocument();
      expect(screen.getByText('Zweite Frage')).toBeInTheDocument();
    });
  });

  it('calls onSelectSession when session clicked', async () => {
    const messages: ChatMessage[] = [
      { id: '1', session_id: 's1', role: 'user', content: 'Test', created_at: '2025-01-01T00:00:00Z' },
    ];
    vi.mocked(getChatHistory).mockResolvedValue({ items: messages, total: 1, page: 1, page_size: 100 });
    const onSelectSession = vi.fn();
    render(<ChatHistory onSelectSession={onSelectSession} onClose={vi.fn()} />);
    await waitFor(() => { expect(screen.getByText('Test')).toBeInTheDocument(); });
    fireEvent.click(screen.getByTestId('history-session-s1'));
    expect(onSelectSession).toHaveBeenCalledWith('s1');
  });
});

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

  it('renders chat interface with input and message list', () => {
    render(<ChatInterface />);
    expect(screen.getByTestId('chat-input')).toBeInTheDocument();
    expect(screen.getByTestId('message-list')).toBeInTheDocument();
    expect(screen.getByTestId('voice-button')).toBeInTheDocument();
  });

  it('sends message and displays response', async () => {
    vi.mocked(sendChatMessage).mockResolvedValue({
      response: 'Ich helfe dir!', actions: [], session_id: 'test-session', message_id: 'msg-1',
    });
    render(<ChatInterface />);
    const input = screen.getByTestId('chat-input') as HTMLTextAreaElement;
    fireEvent.change(input, { target: { value: 'Hallo' } });
    fireEvent.click(screen.getByTestId('send-button'));
    await waitFor(() => { expect(screen.getByText('Ich helfe dir!')).toBeInTheDocument(); });
    expect(sendChatMessage).toHaveBeenCalledWith('Hallo', undefined);
  });

  it('shows action preview when response has actions', async () => {
    vi.mocked(sendChatMessage).mockResolvedValue({
      response: 'Ich suche LKWs.',
      actions: [{ type: 'search_vehicles', params: { type: 'lkw' } }],
      session_id: 'test-session', message_id: 'msg-1',
    });
    render(<ChatInterface />);
    const input = screen.getByTestId('chat-input') as HTMLTextAreaElement;
    fireEvent.change(input, { target: { value: 'Zeige LKWs' } });
    fireEvent.click(screen.getByTestId('send-button'));
    await waitFor(() => { expect(screen.getByTestId('action-preview')).toBeInTheDocument(); });
  });

  it('executes action when confirm button clicked', async () => {
    vi.mocked(sendChatMessage).mockResolvedValue({
      response: 'Ich suche LKWs.',
      actions: [{ type: 'search_vehicles', params: { type: 'lkw' } }],
      session_id: 'test-session', message_id: 'msg-1',
    });
    vi.mocked(executeAction).mockResolvedValue({
      action: 'search_vehicles', result: { items: [], total: 0, page: 1, page_size: 20 }, success: true,
    });
    render(<ChatInterface />);
    const input = screen.getByTestId('chat-input') as HTMLTextAreaElement;
    fireEvent.change(input, { target: { value: 'Zeige LKWs' } });
    fireEvent.click(screen.getByTestId('send-button'));
    await waitFor(() => { expect(screen.getByTestId('action-preview')).toBeInTheDocument(); });
    fireEvent.click(screen.getByTestId('confirm-action-0'));
    await waitFor(() => { expect(executeAction).toHaveBeenCalled(); });
  });

  it('shows error on API failure', async () => {
    vi.mocked(sendChatMessage).mockRejectedValue(new Error('Network error'));
    render(<ChatInterface />);
    const input = screen.getByTestId('chat-input') as HTMLTextAreaElement;
    fireEvent.change(input, { target: { value: 'Test' } });
    fireEvent.click(screen.getByTestId('send-button'));
    await waitFor(() => { expect(screen.getByTestId('chat-error')).toBeInTheDocument(); });
  });

  it('toggles history sidebar', async () => {
    vi.mocked(getChatHistory).mockResolvedValue({ items: [], total: 0, page: 1, page_size: 100 });
    render(<ChatInterface />);
    expect(screen.queryByTestId('chat-history')).not.toBeInTheDocument();
    fireEvent.click(screen.getByTestId('toggle-history'));
    await waitFor(() => { expect(screen.getByTestId('chat-history')).toBeInTheDocument(); });
  });
});
