import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { ResponsePanel } from '../../components/ResponsePanel'
import type { SourceMetadata } from '../../types'

describe('ResponsePanel', () => {
  const mockSources: SourceMetadata[] = [
    {
      filename: 'document1.pdf',
      upload_date: '2024-01-15',
      content_summary: 'Introduction to RAG systems',
      chunk_index: 0,
    },
    {
      filename: 'document2.txt',
      upload_date: '2024-01-16',
      content_summary: 'Advanced retrieval techniques',
      chunk_index: 1,
    },
  ]

  it('shows empty state message when no answer and not loading', () => {
    render(<ResponsePanel answer={null} sources={[]} isLoading={false} error={null} />)
    expect(screen.getByText(/Ask a question to see the answer here/i)).toBeInTheDocument()
  })

  it('shows loading skeletons when isLoading is true', () => {
    render(<ResponsePanel answer={null} sources={[]} isLoading={true} error={null} />)
    const skeletonElements = screen.getAllByTestId('skeleton-line')
    expect(skeletonElements).toHaveLength(5)
    expect(skeletonElements[0]).toHaveClass('w-full')
    expect(skeletonElements[1]).toHaveClass('w-11/12')
    expect(skeletonElements[2]).toHaveClass('w-4/5')
    expect(skeletonElements[3]).toHaveClass('w-3/5')
    expect(skeletonElements[4]).toHaveClass('w-2/5')
  })

  it('shows source skeleton cards during loading', () => {
    render(<ResponsePanel answer={null} sources={[]} isLoading={true} error={null} />)
    const sourceSkeletons = screen.getAllByTestId('source-skeleton')
    expect(sourceSkeletons).toHaveLength(2)
  })

  it('shows error message when error prop is set', () => {
    render(
      <ResponsePanel
        answer={null}
        sources={[]}
        isLoading={false}
        error="Failed to fetch answer"
      />
    )
    expect(screen.getByText(/Failed to fetch answer/i)).toBeInTheDocument()
  })

  it('renders answer text as bullet points', () => {
    const answer = `- First point\n- Second point\n• Third point\nPlain text line`
    render(<ResponsePanel answer={answer} sources={[]} isLoading={false} error={null} />)
    expect(screen.getByText('First point')).toBeInTheDocument()
    expect(screen.getByText('Second point')).toBeInTheDocument()
    expect(screen.getByText('Third point')).toBeInTheDocument()
    expect(screen.getByText('Plain text line')).toBeInTheDocument()
  })

  it('renders source metadata cards', () => {
    render(
      <ResponsePanel
        answer="Test answer"
        sources={mockSources}
        isLoading={false}
        error={null}
      />
    )
    expect(screen.getByText('document1.pdf')).toBeInTheDocument()
    expect(screen.getByText('document2.txt')).toBeInTheDocument()
    expect(screen.getByText('2024-01-15')).toBeInTheDocument()
    expect(screen.getByText('Introduction to RAG systems')).toBeInTheDocument()
    expect(screen.getByText('Advanced retrieval techniques')).toBeInTheDocument()
  })

  it('does not show sources section when sources array is empty', () => {
    render(<ResponsePanel answer="Test answer" sources={[]} isLoading={false} error={null} />)
    expect(screen.queryByText(/sources/i)).not.toBeInTheDocument()
  })

  it('has a toggle button for sources section', () => {
    render(
      <ResponsePanel
        answer="Test answer"
        sources={mockSources}
        isLoading={false}
        error={null}
      />
    )
    const toggleButton = screen.getByTestId('sources-toggle')
    expect(toggleButton).toBeInTheDocument()
    expect(toggleButton).toHaveTextContent('Sources (2)')
  })

  it('toggles sources visibility when clicking toggle button', () => {
    render(
      <ResponsePanel
        answer="Test answer"
        sources={mockSources}
        isLoading={false}
        error={null}
      />
    )
    const toggleButton = screen.getByTestId('sources-toggle')
    const sourcesContainer = screen.getByTestId('sources-container')
    
    expect(sourcesContainer).toBeInTheDocument()
    expect(screen.getByText('document1.pdf')).toBeInTheDocument()
    
    fireEvent.click(toggleButton)
    expect(screen.queryByTestId('sources-container')).not.toBeInTheDocument()
    expect(toggleButton).toHaveTextContent('Sources (2)')
    
    fireEvent.click(toggleButton)
    expect(screen.getByTestId('sources-container')).toBeInTheDocument()
    expect(screen.getByText('document1.pdf')).toBeInTheDocument()
  })

  it('has a copy button when answer is shown', () => {
    render(
      <ResponsePanel
        answer="Test answer"
        sources={[]}
        isLoading={false}
        error={null}
      />
    )
    const copyButton = screen.getByTestId('copy-answer-btn')
    expect(copyButton).toBeInTheDocument()
  })

  it('copies answer to clipboard when copy button is clicked', async () => {
    const mockClipboardWrite = vi.fn().mockResolvedValue(undefined)
    Object.assign(navigator, {
      clipboard: {
        writeText: mockClipboardWrite,
      },
    })

    render(
      <ResponsePanel
        answer="Test answer to copy"
        sources={[]}
        isLoading={false}
        error={null}
      />
    )

    const copyButton = screen.getByTestId('copy-answer-btn')
    fireEvent.click(copyButton)

    expect(mockClipboardWrite).toHaveBeenCalledWith('Test answer to copy')
    await waitFor(() => {
      expect(screen.getByText('Copied!')).toBeInTheDocument()
    })
  })
})
