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

import { setLocale } from '../src/i18n';
import ChatMessageList from '../src/components/chat/ChatMessageList';

const mocks = vi.hoisted(() => ({
  apiOpenSkillPath: vi.fn(),
  apiOpenSkillReadme: vi.fn(),
  writeText: vi.fn(),
}));

vi.mock('../src/lib/skills-api', () => ({
  apiOpenSkillPath: mocks.apiOpenSkillPath,
  apiOpenSkillReadme: mocks.apiOpenSkillReadme,
}));

describe('ChatMessageList', () => {
  beforeEach(() => {
    setLocale('en');
    vi.clearAllMocks();
    mocks.apiOpenSkillPath.mockResolvedValue(undefined);
    mocks.apiOpenSkillReadme.mockResolvedValue(undefined);
    mocks.writeText.mockResolvedValue(undefined);
    Object.defineProperty(window.navigator, 'clipboard', {
      value: {
        writeText: mocks.writeText,
      },
      configurable: true,
    });
  });

  it('renders standalone streaming tool status cards when there is no streaming assistant text yet', () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'user-1',
            role: 'user',
            name: 'Me',
            time: '10:00',
            content: 'Install this skill for me.',
          },
        ]}
        streamingTools={[
          {
            id: 'tool-1',
            toolCallId: 'skills.install:run-1',
            name: 'skills.install',
            status: 'running',
            summary: 'Installing minimax-xlsx',
            updatedAt: Date.now(),
          },
        ]}
      />,
    );

    expect(screen.getByText('Running tools...')).toBeTruthy();
    expect(screen.getByText('Install Skill')).toBeTruthy();
    expect(screen.getByText('Running')).toBeTruthy();
    expect(screen.getByText('Installing minimax-xlsx')).toBeTruthy();
  });

  it('renders streaming tool status cards above a streaming assistant message', () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'assistant-stream',
            role: 'assistant',
            name: 'YINIAN',
            time: '10:01',
            content: 'The page is open.',
            isStreaming: true,
          },
        ]}
        streamingTools={[
          {
            id: 'tool-2',
            toolCallId: 'browser.open_url:run-2',
            name: 'browser.open_url',
            status: 'completed',
            durationMs: 1200,
            summary: 'Opened http://www.baidu.com/',
            updatedAt: Date.now(),
          },
        ]}
      />,
    );

    expect(screen.getByText('Open Webpage')).toBeTruthy();
    expect(screen.getByText('Completed')).toBeTruthy();
    expect(screen.getByText('1.2s')).toBeTruthy();
    expect(screen.getByText('Opened http://www.baidu.com/')).toBeTruthy();
    expect(screen.getByText('The page is open.')).toBeTruthy();
  });

  it('renders persistent skill-install tool cards with follow-up actions', async () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'assistant-1',
            role: 'assistant',
            name: 'YINIAN',
            time: '10:03',
            content: 'Installed and enabled minimax-xlsx at /tmp/minimax-xlsx',
            toolStatuses: [
              {
                id: 'tool-3',
                toolCallId: 'skills.install:run-3',
                name: 'skills.install',
                status: 'completed',
                summary: 'Installed and enabled minimax-xlsx at /tmp/minimax-xlsx',
                durationMs: 980,
                updatedAt: Date.now(),
                input: {
                  kind: 'github-url',
                  url: 'https://github.com/MiniMax-AI/skills/blob/main/skills/minimax-xlsx/SKILL.md',
                },
                result: {
                  slug: 'minimax-xlsx',
                  source: 'github-url',
                  baseDir: '/tmp/minimax-xlsx',
                },
              },
            ],
          },
        ]}
      />,
    );

    expect(screen.getAllByText('Installed and enabled minimax-xlsx at /tmp/minimax-xlsx')).toHaveLength(1);
    expect(screen.getByText('Skill')).toBeTruthy();
    expect(screen.getByText('/tmp/minimax-xlsx')).toBeTruthy();
    expect(screen.getByText('Next actions')).toBeTruthy();

    fireEvent.click(screen.getByText('Open folder'));
    await waitFor(() => {
      expect(mocks.apiOpenSkillPath).toHaveBeenCalledWith(
        'minimax-xlsx',
        'minimax-xlsx',
        '/tmp/minimax-xlsx',
      );
    });

    fireEvent.click(screen.getByText('Copy path'));
    await waitFor(() => {
      expect(mocks.writeText).toHaveBeenCalledWith('/tmp/minimax-xlsx');
    });
    expect(screen.getByText('Path copied')).toBeTruthy();
  });

  it('renders spreadsheet analysis cards from structured tool results', () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'assistant-sheet',
            role: 'assistant',
            name: 'YINIAN',
            time: '10:05',
            content: '',
            toolStatuses: [
              {
                id: 'tool-4',
                toolCallId: 'minimax-xlsx:run-4',
                name: 'minimax-xlsx',
                status: 'completed',
                summary: 'Analyzed 1 spreadsheet attachment.',
                updatedAt: Date.now(),
                result: {
                  ok: true,
                  summary: 'Analyzed 1 spreadsheet attachment.',
                  renderHints: {
                    card: 'document-analysis',
                    preferredView: 'table',
                    skillType: 'spreadsheet',
                  },
                  artifacts: [
                    {
                      kind: 'file',
                      name: 'hotel-sales.xls',
                      filePath: 'F:\\Downloads\\hotel-sales.xls',
                    },
                  ],
                  structuredData: {
                    reports: [
                      {
                        fileName: 'hotel-sales.xls',
                        filePath: 'F:\\Downloads\\hotel-sales.xls',
                        report: {
                          engine: 'node-xlsx',
                          workbook: {
                            sheetNames: ['Grid Results'],
                            totalRows: 18358,
                          },
                          structure: {
                            'Grid Results': {
                              shape: {
                                rows: 18358,
                                cols: 12,
                              },
                              columns: ['channel', 'sales_amount', 'sales_date', 'room_type'],
                              preview: [
                                {
                                  channel: 'Douyin',
                                  sales_amount: 615.53,
                                  sales_date: '2025-08-10',
                                  room_type: 'Superior Twin',
                                },
                                {
                                  channel: 'Ctrip',
                                  sales_amount: 983.15,
                                  sales_date: '2025-08-11',
                                  room_type: 'Parent Child',
                                },
                              ],
                            },
                          },
                          quality: {
                            'Grid Results': [
                              {
                                type: 'missing_values',
                                message: 'sales_date missing in 2,566 rows',
                              },
                            ],
                          },
                        },
                      },
                    ],
                  },
                },
              },
            ],
          },
        ]}
      />,
    );

    const spreadsheetCard = screen.getByTestId('tool-spreadsheet-preview');
    expect(within(spreadsheetCard).getByText('Analysis overview')).toBeTruthy();
    expect(within(spreadsheetCard).getByText('1 file')).toBeTruthy();
    expect(within(spreadsheetCard).getAllByText('1 sheet').length).toBeGreaterThan(0);
    expect(within(spreadsheetCard).getAllByText('18,358 rows').length).toBeGreaterThan(0);
    expect(within(spreadsheetCard).getByText('hotel-sales.xls')).toBeTruthy();
    expect(within(spreadsheetCard).getByText('Grid Results')).toBeTruthy();
    expect(within(spreadsheetCard).getByText('12 cols')).toBeTruthy();
    expect(within(spreadsheetCard).getByText(/Columns: channel, sales_amount, sales_date, room_type/)).toBeTruthy();
    expect(within(spreadsheetCard).getByText('Douyin')).toBeTruthy();
    expect(within(spreadsheetCard).getByText('615.53')).toBeTruthy();
    expect(within(spreadsheetCard).getByText('sales_date missing in 2,566 rows')).toBeTruthy();
    expect(screen.getByText('Artifacts')).toBeTruthy();
    expect(screen.getByText('F:\\Downloads\\hotel-sales.xls')).toBeTruthy();
  });

  it('renders generic document-analysis structured data when there is no spreadsheet preview', () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'assistant-doc',
            role: 'assistant',
            name: 'YINIAN',
            time: '10:06',
            content: '',
            toolStatuses: [
              {
                id: 'tool-5',
                toolCallId: 'doc-skill:run-5',
                name: 'contract-analyzer',
                status: 'completed',
                summary: 'Reviewed the contract package.',
                updatedAt: Date.now(),
                result: {
                  ok: true,
                  renderHints: {
                    card: 'document-analysis',
                    preferredView: 'table',
                    skillType: 'document',
                  },
                  structuredData: {
                    confidence: 0.94,
                    documents: ['master-service-agreement.pdf'],
                    findings: [
                      {
                        section: 'Termination',
                        status: 'Needs review',
                      },
                      {
                        section: 'Payment',
                        status: 'OK',
                      },
                    ],
                  },
                },
              },
            ],
          },
        ]}
      />,
    );

    const structuredCard = screen.getByTestId('tool-structured-result');
    expect(within(structuredCard).getByText('Structured result')).toBeTruthy();
    expect(within(structuredCard).getByText('Confidence')).toBeTruthy();
    expect(within(structuredCard).getByText('0.94')).toBeTruthy();
    expect(within(structuredCard).getByText('Documents')).toBeTruthy();
    expect(within(structuredCard).getByText('master-service-agreement.pdf')).toBeTruthy();
    expect(within(structuredCard).getByText('Termination')).toBeTruthy();
    expect(within(structuredCard).getByText('Needs review')).toBeTruthy();
  });

  it('renders dedicated search result cards for search-family tool results', () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'assistant-search',
            role: 'assistant',
            name: 'YINIAN',
            time: '10:08',
            content: '',
            toolStatuses: [
              {
                id: 'tool-6',
                toolCallId: 'brave-web-search:run-6',
                name: 'brave-web-search',
                status: 'completed',
                summary: 'Search completed with Brave Web Search.',
                updatedAt: Date.now(),
                result: {
                  ok: true,
                  renderHints: {
                    card: 'search-results',
                    preferredView: 'summary',
                    skillType: 'search',
                  },
                  structuredData: {
                    provider: 'brave',
                    query: 'hotel revenue trends',
                    answer: 'Revenue continues to improve across the sector.',
                    responseTimeMs: 820,
                    resultCount: 2,
                    results: [
                      {
                        title: 'Hotel Revenue Trends Q1',
                        url: 'https://example.com/revenue-q1',
                        snippet: 'Revenue increased across the segment.',
                        source: 'Example News',
                        score: 0.9821,
                      },
                      {
                        title: 'Demand Outlook',
                        url: 'https://example.com/demand',
                        snippet: 'Demand remains resilient.',
                        source: 'Industry Daily',
                      },
                    ],
                  },
                },
              },
            ],
          },
        ]}
      />,
    );

    const searchCard = screen.getByTestId('tool-search-results');
    expect(within(searchCard).getByText('Search overview')).toBeTruthy();
    expect(within(searchCard).getByText('Provider: brave')).toBeTruthy();
    expect(within(searchCard).getByText('2 results')).toBeTruthy();
    expect(within(searchCard).getByText('Query')).toBeTruthy();
    expect(within(searchCard).getByText('hotel revenue trends')).toBeTruthy();
    expect(within(searchCard).getByText('Answer')).toBeTruthy();
    expect(within(searchCard).getByText('Revenue continues to improve across the sector.')).toBeTruthy();
    expect(within(searchCard).getByText('Hotel Revenue Trends Q1')).toBeTruthy();
    expect(within(searchCard).getByText('https://example.com/revenue-q1')).toBeTruthy();
    expect(within(searchCard).getByText('Source: Example News')).toBeTruthy();
    expect(within(searchCard).getByText('Score: 0.9821')).toBeTruthy();
  });

  it('renders install commands in the search result card for command-style tool results', () => {
    render(
      <ChatMessageList
        messages={[
          {
            id: 'assistant-find-skills',
            role: 'assistant',
            name: 'YINIAN',
            time: '10:09',
            content: '',
            toolStatuses: [
              {
                id: 'tool-7',
                toolCallId: 'find-skills:run-7',
                name: 'find-skills',
                status: 'completed',
                summary: 'Found 1 matching skill result.',
                updatedAt: Date.now(),
                result: {
                  ok: true,
                  renderHints: {
                    card: 'search-results',
                    preferredView: 'summary',
                    skillType: 'command',
                  },
                  structuredData: {
                    provider: 'clawhub',
                    query: 'react performance',
                    resultCount: 1,
                    results: [
                      {
                        title: 'react-best-practices',
                        url: 'https://skills.sh/vercel-labs/agent-skills/react-best-practices',
                        snippet: 'React and Next.js guidance from Vercel.',
                        installCommand: 'npx skills add vercel-labs/agent-skills@react-best-practices -g -y',
                      },
                    ],
                  },
                },
              },
            ],
          },
        ]}
      />,
    );

    const searchCard = screen.getByTestId('tool-search-results');
    expect(within(searchCard).getByText('react-best-practices')).toBeTruthy();
    expect(within(searchCard).getByText('Install command')).toBeTruthy();
    expect(within(searchCard).getByText('npx skills add vercel-labs/agent-skills@react-best-practices -g -y')).toBeTruthy();
  });
});
