import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
import AssistantChatPanel from '../AssistantChatPanel.svelte';
import * as api from '$lib/api/assistant.js';
import { assistantChatStore } from '$lib/stores/assistantChat.svelte.js';

// Mock dependencies
vi.mock('$lib/api/assistant.js', () => ({
  getAssistantHistory: vi.fn(),
  confirmAssistantOperation: vi.fn(),
  cancelAssistantOperation: vi.fn(),
  getAssistantConversations: vi.fn(() => Promise.resolve({ items: [], total: 0 })),
  sendAssistantMessage: vi.fn()
}));

vi.mock('$lib/api', () => ({
  api: {
    getLlmStatus: vi.fn(() => Promise.resolve({ configured: true })),
    fetchApi: vi.fn((endpoint) => {
      if (endpoint === '/dataset-orchestration/sessions/session-1/clarification') {
        return Promise.resolve(null);
      }
      if (endpoint === '/dataset-orchestration/sessions/session-1') {
        return Promise.resolve({ session_id: 'session-1', session_version: 2, version: 2 });
      }
      return Promise.resolve(null);
    })
  },
  requestApi: vi.fn(),
}));

vi.mock('$lib/toasts.svelte.js', () => ({
  addToast: vi.fn()
}));

const mockAssistantState = { isOpen: true, conversationId: 'conv-1', datasetReviewSessionId: 'session-1', seedMessage: '', focusTarget: { target: 'mapping:m-1', source: 'test' } };
vi.mock('$lib/stores/assistantChat.svelte.js', () => ({
  assistantChatStore: {
    subscribe: (fn) => {
      fn(mockAssistantState);
      return () => { };
    },
    get value() { return mockAssistantState; },
  },
  closeAssistantChat: vi.fn(),
  setAssistantConversationId: vi.fn(),
  setAssistantSeedMessage: vi.fn(),
  setAssistantFocusTarget: vi.fn(),
}));

vi.mock('$app/navigation', () => ({
  goto: vi.fn()
}));

const mockTranslations = {
  assistant: {
    action_failed: 'Action failed',
    confirm: 'Confirm',
    cancel: 'Cancel',
    title: 'Assistant',
    close: 'Close',
    loading_history: 'Loading history...',
    try_commands: 'Try commands',
    sample_command_branch: 'branch',
    sample_command_migration: 'migration',
    sample_command_status: 'status',
    you: 'You',
    assistant: 'Assistant',
    states: {
      needs_confirmation: 'Needs confirmation',
      failed: 'Failed'
    },
    task_id: 'task_id',
    open_task_drawer: 'Open Task Drawer',
    input_placeholder: 'Type a command...',
    send: 'Send',
    conversations: 'Conversations',
    new: 'New',
    active: 'Active',
    archived: 'Archived',
    more: 'More',
    session_scope_title: 'Active review context',
    session_scope_label: 'Session',
    focus_target_label: 'Focus',
    clear_focus_action: 'Clear focus',
    confirmation_card_title: 'Confirmation required',
    confirmation_scope_fallback: 'This action affects the current assistant scope.',
    confirmation_operation_label: 'Action',
    highlight_workspace_action: 'Highlight in workspace',
  }
};
vi.mock('$lib/i18n/index.svelte.js', () => ({
  t: {
    subscribe: (fn) => {
      fn(mockTranslations);
      return () => { };
    }
  },
  getT: vi.fn(() => mockTranslations),
  _: vi.fn((key) => key),
}));

describe('AssistantChatPanel confirmation functional tests', () => {
  const mockMessage = {
    message_id: 'msg-123',
    role: 'assistant',
    text: 'Confirm migration?',
    state: 'needs_confirmation',
    created_at: new Date().toISOString(),
    conversation_id: 'conv-1',
    confirmation_id: 'conf-123',
    intent: {
      operation: 'approve_all_mapping_warnings',
      remaining_blockers: ['Preview is stale'],
      open_warning_refs: ['mapping:m-1']
    },
    actions: [
      { type: 'confirm', label: 'Confirm' },
      { type: 'cancel', label: 'Cancel' },
      { type: 'focus_target', label: 'Highlight', target: 'mapping:m-1' }
    ]
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders action buttons and triggers confirm API call', async () => {
    // Mock getAssistantHistory to return our message
    api.getAssistantHistory.mockImplementation(async () => ({
      items: [mockMessage],
      total: 1,
      has_next: false
    }));

    render(AssistantChatPanel);

    // Wait for message to render
    const confirmBtn = await screen.findByText('Confirm', {}, { timeout: 3000 });
    expect(confirmBtn).toBeTruthy();

    await fireEvent.click(confirmBtn);

    expect(api.confirmAssistantOperation).toHaveBeenCalledWith('conf-123');
  });

  it('triggers cancel API call when cancel button is clicked', async () => {
    api.getAssistantHistory.mockImplementation(async () => ({
      items: [mockMessage],
      total: 1,
      has_next: false
    }));

    render(AssistantChatPanel);

    const cancelBtn = await screen.findByText('Cancel', {}, { timeout: 3000 });
    await fireEvent.click(cancelBtn);

    expect(api.cancelAssistantOperation).toHaveBeenCalledWith('conf-123');
  });

  it('shows toast error when action fails', async () => {
    api.getAssistantHistory.mockImplementation(async () => ({
      items: [mockMessage],
      total: 1,
      has_next: false
    }));
    api.confirmAssistantOperation.mockImplementation(async () => {
      throw new Error('Network error');
    });

    render(AssistantChatPanel);

    const confirmBtn = await screen.findByText('Confirm', {}, { timeout: 3000 });
    await fireEvent.click(confirmBtn);

    await waitFor(() => {
      // The component appends a failed message to the chat
      expect(screen.getAllByText(/Network error/)).toBeTruthy();
    }, { timeout: 3000 });
  });

  it('renders confirmation card scope details for dataset review actions', async () => {
    api.getAssistantHistory.mockImplementation(async () => ({
      items: [mockMessage],
      total: 1,
      has_next: false
    }));

    render(AssistantChatPanel);

    expect(await screen.findByText('Confirmation required', {}, { timeout: 3000 })).toBeTruthy();
    expect(screen.getAllByText(/Session: session-1/).length).toBeGreaterThan(0);
    expect(screen.getByText(/approve_all_mapping_warnings/)).toBeTruthy();
    expect(screen.getByText(/Preview is stale/)).toBeTruthy();
    expect(screen.getAllByText(/mapping:m-1/).length).toBeGreaterThan(0);
  });
});
