import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { MapCharacterPanel } from '../../src/components/characters/MapCharacterPanel';

const {
  mockGetShopItems,
  mockGetGoldBalance,
  mockSendNpcMessage,
  mockGetNpcChatSession,
  mockStartNpcChat,
} = vi.hoisted(() => ({
  mockGetShopItems: vi.fn().mockResolvedValue([]),
  mockGetGoldBalance: vi.fn().mockResolvedValue(300),
  mockSendNpcMessage: vi.fn().mockResolvedValue({
    messages: [],
    balance: { gold: 300 },
    negotiation: { status: 'active' },
    shop_items: [],
  }),
  mockGetNpcChatSession: vi.fn().mockResolvedValue({ messages: [] }),
  mockStartNpcChat: vi.fn().mockResolvedValue({ messages: [] }),
}));

const mockUseCharacter = vi.fn();

vi.mock('../../src/store/characterStore', () => ({
  useCharacter: () => mockUseCharacter(),
}));

vi.mock('../../src/services/api', () => ({
  apiService: {
    getShopItems: mockGetShopItems,
    getGoldBalance: mockGetGoldBalance,
    sendNpcMessage: mockSendNpcMessage,
    getNpcChatSession: mockGetNpcChatSession,
    startNpcChat: mockStartNpcChat,
  },
}));

describe('MapCharacterPanel rich chat formatting', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockGetShopItems.mockResolvedValue([]);
    mockGetGoldBalance.mockResolvedValue(300);
    mockSendNpcMessage.mockResolvedValue({
      messages: [],
      balance: { gold: 300 },
      negotiation: { status: 'active' },
      shop_items: [],
    });
    mockGetNpcChatSession.mockResolvedValue({ messages: [] });
    mockStartNpcChat.mockResolvedValue({ messages: [] });
    mockUseCharacter.mockReturnValue({
      activeCharacter: 'frodo',
      setActiveCharacter: vi.fn(),
      isChatLoading: false,
      chatMessages: [
        {
          role: 'assistant',
          content: "- **Elven Cloak** — ask **88 Gold**\n- **Ranger's Rope** — ask **40 Gold**",
          format: 'markdown',
          type: 'assistant',
        },
      ],
      setChatMessages: vi.fn(),
      setChatLoading: vi.fn(),
    });
  });

  it('renders bold prices and list-like bargaining messages', () => {
    render(<MapCharacterPanel />);

    expect(screen.getByText('Elven Cloak', { selector: 'strong' })).toBeTruthy();
    expect(screen.getByText('88 Gold', { selector: 'strong' })).toBeTruthy();
    expect(screen.getByText("Ranger's Rope", { selector: 'strong' })).toBeTruthy();
  });

  it('loads the wares catalog directly instead of opening with generic chat opener', async () => {
    const setChatMessages = vi.fn();
    const catalogMessages = [
      {
        role: 'assistant',
        content: 'Available wares to bargain for:\n- **Shire Herb Satchel** — ask **120 Gold** (id: #2)',
        format: 'markdown',
        type: 'assistant',
        metadata: { kind: 'shop-catalog' },
      },
    ];

    mockUseCharacter.mockReturnValue({
      activeCharacter: 'sam',
      setActiveCharacter: vi.fn(),
      isChatLoading: false,
      chatMessages: [],
      setChatMessages,
      setChatLoading: vi.fn(),
    });
    mockGetNpcChatSession.mockResolvedValue({ messages: [] });
    mockSendNpcMessage.mockResolvedValue({
      messages: catalogMessages,
      balance: { gold: 300 },
      negotiation: { status: 'catalog' },
      shop_items: [],
    });

    render(<MapCharacterPanel />);

    await waitFor(() => {
      expect(mockSendNpcMessage).toHaveBeenCalledWith('sam', 'shop');
    });
    expect(mockStartNpcChat).not.toHaveBeenCalled();
    expect(setChatMessages).toHaveBeenCalledWith(catalogMessages);
  });
});