import { describe, expect, it, vi } from 'vitest'

import { fireEvent, renderWithProviders, screen } from '../../test/utils'

import { triggerDownload } from './_shared/triggerDownload'
import { bubbleVariantForState, bubbleGroupPositionFromStream } from './types'

import MessageAttachment from '.'

vi.mock('./_shared/triggerDownload', () => ({
  triggerDownload: vi.fn(() => Promise.resolve()),
}))

const mockedDownload = vi.mocked(triggerDownload)

describe('MessageAttachment behavior', () => {
  it('renders file rows with precedence, fallback names, and cancellation', () => {
    const onClick = vi.fn(() => false)
    const { rerender } = renderWithProviders(
      <MessageAttachment.File.Sent
        src="https://cdn.example.com/fallback.txt"
        filename="fallback.txt"
        items={[
          {
            src: 'https://cdn.example.com/first.pdf',
            filename: 'first.pdf',
          },
          { src: 'https://cdn.example.com/second.pdf' },
        ]}
        onClick={onClick}
      />
    )
    expect(screen.getByText('first.pdf')).toBeInTheDocument()
    expect(screen.getByText('second.pdf')).toBeInTheDocument()
    fireEvent.click(screen.getByRole('button', { name: 'Download first.pdf' }))
    expect(onClick).toHaveBeenCalledWith(0)
    expect(mockedDownload).not.toHaveBeenCalled()

    rerender(
      <MessageAttachment.File.Sent src="https://cdn.example.com/fallback.txt" />
    )
    fireEvent.click(
      screen.getByRole('button', { name: 'Download fallback.txt' })
    )
    expect(mockedDownload).toHaveBeenCalledWith(
      'https://cdn.example.com/fallback.txt',
      'fallback.txt'
    )
  })

  it('renders no file when inputs are absent and supports composer dismissal', () => {
    const { container } = renderWithProviders(
      <MessageAttachment.File.Received />
    )
    expect(container.firstChild).toBeNull()
    const onDismiss = vi.fn()
    renderWithProviders(
      <MessageAttachment.File.Composer
        src="https://cdn.example.com/file"
        onDismiss={onDismiss}
      />
    )
    fireEvent.click(screen.getByRole('button', { name: 'Dismiss attachment' }))
    expect(onDismiss).toHaveBeenCalledOnce()
  })

  it('renders image stacks, forwards loading, and supports click cancellation', () => {
    const onClick = vi.fn(() => false)
    renderWithProviders(
      <MessageAttachment.Image.Sent
        src="https://cdn.example.com/fallback.jpg"
        items={[
          { src: 'https://cdn.example.com/one.jpg' },
          { src: 'https://cdn.example.com/two.jpg', loading: 'eager' },
        ]}
        loading="lazy"
        onClick={onClick}
      />
    )
    expect(screen.getAllByRole('img')[0]).toHaveAttribute('loading', 'lazy')
    expect(screen.getAllByRole('img')).toHaveLength(2)
    fireEvent.click(screen.getByRole('button', { name: 'Open image 2 of 2' }))
    expect(onClick).toHaveBeenCalledWith(1)
    expect(screen.queryByTestId('image-viewer')).not.toHaveAttribute('open')
  })

  it('opens images at the clicked index and suffixes a shared filename', () => {
    renderWithProviders(
      <MessageAttachment.Image.Sent
        filename="photos.jpg"
        items={[
          { src: 'https://cdn.example.com/one.jpg' },
          { src: 'https://cdn.example.com/two.jpg' },
        ]}
      />
    )
    fireEvent.click(screen.getByRole('button', { name: 'Open image 2 of 2' }))
    expect(screen.getByTestId('image-viewer')).toHaveAttribute(
      'aria-label',
      'photos.jpg (2)'
    )
    expect(screen.getByRole('img', { name: 'photos.jpg (2)' })).toHaveAttribute(
      'src',
      'https://cdn.example.com/two.jpg'
    )
  })

  it('renders video poster and fallback, and wires viewer attributes', () => {
    const onDismiss = vi.fn()
    const { rerender } = renderWithProviders(
      <MessageAttachment.Video.Composer
        src="https://cdn.example.com/video.mp4"
        poster="/poster.jpg"
        mimeType="video/mp4"
        preload="auto"
        onDismiss={onDismiss}
      />
    )
    expect(
      screen.getByRole('img', { name: 'Video 1 thumbnail' })
    ).toHaveAttribute('src', '/poster.jpg')
    fireEvent.click(screen.getByRole('button', { name: 'Dismiss attachment' }))
    expect(onDismiss).toHaveBeenCalledOnce()
    rerender(
      <MessageAttachment.Video.Sent
        items={[{ src: 'https://cdn.example.com/video.mp4' }]}
      />
    )
    expect(screen.getByLabelText('Play video 1 of 1')).toBeInTheDocument()
  })

  it('supports PDF titles, download actions, dismiss, and viewer index', () => {
    const onDismiss = vi.fn()
    renderWithProviders(
      <MessageAttachment.Pdf.Composer
        src="https://cdn.example.com/report.pdf"
        title="Quarterly report"
        onDismiss={onDismiss}
      />
    )
    expect(screen.getByText('Quarterly report')).toBeInTheDocument()
    fireEvent.click(screen.getByRole('button', { name: 'Dismiss attachment' }))
    expect(onDismiss).toHaveBeenCalledOnce()

    renderWithProviders(
      <MessageAttachment.Pdf.Sent
        items={[
          { src: 'https://cdn.example.com/one.pdf' },
          { src: 'https://cdn.example.com/two.pdf', filename: 'two.pdf' },
        ]}
      />
    )
    fireEvent.click(screen.getByRole('button', { name: 'Open two.pdf' }))
    expect(screen.getAllByTestId('pdf-viewer').at(-1)).toHaveAttribute(
      'aria-label',
      'two.pdf'
    )
  })

  it('maps state and stream grouping contracts', () => {
    expect(bubbleVariantForState('composer')).toBe('dark')
    expect(bubbleVariantForState('sent')).toBe('dark')
    expect(bubbleVariantForState('received')).toBe('light')
    expect(bubbleGroupPositionFromStream({})).toBe('single')
    expect(
      bubbleGroupPositionFromStream({
        groupedByUser: true,
        firstOfGroup: true,
        endOfGroup: true,
      })
    ).toBe('single')
    expect(
      bubbleGroupPositionFromStream({ groupedByUser: true, firstOfGroup: true })
    ).toBe('first')
    expect(
      bubbleGroupPositionFromStream({ groupedByUser: true, endOfGroup: true })
    ).toBe('end')
    expect(bubbleGroupPositionFromStream({ groupedByUser: true })).toBe(
      'middle'
    )
  })
})
