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

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

import DownloadAction from './DownloadAction'
import { triggerDownload } from './triggerDownload'
import { VIEWER_ACTION_CLASS } from './viewerChromeClasses'

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

const mockedTriggerDownload = vi.mocked(triggerDownload)

beforeEach(() => {
  mockedTriggerDownload.mockReset()
  mockedTriggerDownload.mockResolvedValue(undefined)
})

describe('DownloadAction', () => {
  it('uses a visible label for the default pill variant', () => {
    renderWithProviders(<DownloadAction url="/file.pdf" />)
    const button = screen.getByRole('button', { name: 'Download' })
    expect(button).toHaveTextContent('Download')
    expect(button).not.toHaveAttribute('aria-label')
  })

  it.each(['inline', 'viewer'] as const)(
    'uses an accessible-only label for the %s variant',
    (variant) => {
      renderWithProviders(
        <DownloadAction url="/file.pdf" variant={variant} label="Save file" />
      )
      const button = screen.getByRole('button', { name: 'Save file' })
      expect(button).not.toHaveTextContent('Save file')
    }
  )

  it('allows iconOnly to control the pill label', () => {
    const { rerender } = renderWithProviders(
      <DownloadAction url="/file.pdf" label="Save" iconOnly />
    )
    expect(screen.getByRole('button', { name: 'Save' })).not.toHaveTextContent(
      'Save'
    )
    rerender(<DownloadAction url="/file.pdf" label="Save" iconOnly={false} />)
    expect(screen.getByRole('button', { name: 'Save' })).toHaveTextContent(
      'Save'
    )
  })

  it.each(['inline', 'viewer'] as const)(
    'keeps the %s label visually hidden regardless of iconOnly',
    (variant) => {
      const { rerender } = renderWithProviders(
        <DownloadAction
          url="/file.pdf"
          variant={variant}
          label="Save"
          iconOnly={false}
        />
      )
      expect(
        screen.getByRole('button', { name: 'Save' })
      ).not.toHaveTextContent('Save')
      rerender(
        <DownloadAction
          url="/file.pdf"
          variant={variant}
          label="Save"
          iconOnly
        />
      )
      expect(
        screen.getByRole('button', { name: 'Save' })
      ).not.toHaveTextContent('Save')
    }
  )

  it('stops propagation and calls the download once', async () => {
    const outerClick = vi.fn()
    renderWithProviders(
      // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
      <div onClick={outerClick}>
        <DownloadAction
          url="/file.pdf"
          filename="report.pdf"
          onTriggered={vi.fn()}
        />
      </div>
    )
    fireEvent.click(screen.getByRole('button', { name: 'Download' }))
    await waitFor(() =>
      expect(mockedTriggerDownload).toHaveBeenCalledWith(
        '/file.pdf',
        'report.pdf'
      )
    )
    expect(mockedTriggerDownload).toHaveBeenCalledOnce()
    expect(outerClick).not.toHaveBeenCalled()
  })

  it('disables repeated clicks while downloading and settles on success', async () => {
    let resolve: () => void = () => undefined
    mockedTriggerDownload.mockReturnValueOnce(
      new Promise<void>((done) => {
        resolve = done
      })
    )
    const onTriggered = vi.fn()
    renderWithProviders(
      <DownloadAction url="/file.pdf" onTriggered={onTriggered} />
    )
    const button = screen.getByRole('button', { name: 'Download' })
    fireEvent.click(button)
    fireEvent.click(button)
    expect(button).toBeDisabled()
    expect(mockedTriggerDownload).toHaveBeenCalledOnce()
    resolve()
    await waitFor(() => expect(button).toBeEnabled())
    expect(onTriggered).toHaveBeenCalledOnce()
  })

  it('settles and notifies even when downloading rejects', async () => {
    mockedTriggerDownload.mockRejectedValueOnce(new Error('offline'))
    const onTriggered = vi.fn()
    renderWithProviders(
      <DownloadAction url="/file.pdf" onTriggered={onTriggered} />
    )
    const button = screen.getByRole('button', { name: 'Download' })
    fireEvent.click(button)
    await waitFor(() => expect(button).toBeEnabled())
    expect(onTriggered).toHaveBeenCalledOnce()
  })

  it('maps tone classes for pill and inline variants', () => {
    const { rerender } = renderWithProviders(
      <DownloadAction url="/file.pdf" tone="dark" />
    )
    expect(screen.getByRole('button', { name: 'Download' })).toHaveClass(
      'hover:bg-[#2a2928]'
    )
    rerender(<DownloadAction url="/file.pdf" tone="light" />)
    expect(screen.getByRole('button', { name: 'Download' })).toHaveClass(
      'hover:bg-white/90'
    )
    rerender(<DownloadAction url="/file.pdf" variant="inline" tone="dark" />)
    expect(screen.getByRole('button', { name: 'Download' })).toHaveClass(
      'hover:text-white'
    )
    rerender(<DownloadAction url="/file.pdf" variant="inline" tone="light" />)
    expect(screen.getByRole('button', { name: 'Download' })).toHaveClass(
      'hover:text-black'
    )
  })

  it('uses the shared viewer action class', () => {
    renderWithProviders(<DownloadAction url="/file.pdf" variant="viewer" />)
    expect(screen.getByRole('button', { name: 'Download' })).toHaveClass(
      VIEWER_ACTION_CLASS
    )
  })
})
