import type { EnableType } from '../../../types'
import type { FileUpload } from '@/app/components/base/features/types'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Operation from '../operation'

vi.mock('@/app/components/base/file-uploader', () => ({
  FileUploaderInChatInput: ({ readonly }: { readonly?: boolean }) => (
    <div data-testid="file-uploader" data-readonly={readonly} />
  ),
}))

describe('Operation', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  describe('Rendering', () => {
    it('should render send button always', () => {
      render(<Operation onSend={vi.fn()} />)

      expect(screen.getByRole('button'))!.toBeInTheDocument()
    })

    it('should render file uploader when fileConfig.enabled is true', () => {
      const fileConfig: FileUpload = { enabled: true } as FileUpload

      render(<Operation onSend={vi.fn()} fileConfig={fileConfig} />)

      expect(screen.getByTestId('file-uploader'))!.toBeInTheDocument()
    })

    it('should not render file uploader when fileConfig is undefined', () => {
      render(<Operation onSend={vi.fn()} />)

      expect(screen.queryByTestId('file-uploader')).not.toBeInTheDocument()
    })

    it('should render voice input button when speech-to-text is enabled with a handler', () => {
      const speechConfig: EnableType = { enabled: true }

      render(
        <Operation onSend={vi.fn()} speechToTextConfig={speechConfig} onShowVoiceInput={vi.fn()} />,
      )

      expect(screen.getByRole('button', { name: 'common.voiceInput.start' })).toBeInTheDocument()
      expect(screen.getByRole('button', { name: 'common.operation.send' })).toBeInTheDocument()
    })

    it('should render file upload before voice input when both actions are enabled', () => {
      const fileConfig: FileUpload = { enabled: true } as FileUpload
      const speechConfig: EnableType = { enabled: true }

      render(
        <Operation
          onSend={vi.fn()}
          fileConfig={fileConfig}
          speechToTextConfig={speechConfig}
          onShowVoiceInput={vi.fn()}
        />,
      )

      const fileUploader = screen.getByTestId('file-uploader')
      const voiceButton = screen.getByRole('button', { name: 'common.voiceInput.start' })

      expect(
        fileUploader.compareDocumentPosition(voiceButton) & Node.DOCUMENT_POSITION_FOLLOWING,
      ).toBeTruthy()
    })

    it('should not render voice input button when speechToTextConfig.enabled is false', () => {
      const speechConfig: EnableType = { enabled: false }

      render(<Operation onSend={vi.fn()} speechToTextConfig={speechConfig} />)

      expect(screen.getAllByRole('button')).toHaveLength(1)
    })
  })

  describe('Send Button Behavior', () => {
    it('should call onSend when clicked and not readonly', async () => {
      const user = userEvent.setup()
      const onSend = vi.fn()

      render(<Operation onSend={onSend} />)

      await user.click(screen.getByRole('button'))

      expect(onSend).toHaveBeenCalledTimes(1)
    })

    it('should not call onSend when readonly is true', async () => {
      const user = userEvent.setup()
      const onSend = vi.fn()

      render(<Operation onSend={onSend} readonly />)

      await user.click(screen.getByRole('button'))

      expect(onSend).not.toHaveBeenCalled()
    })
  })

  describe('Voice Input Button', () => {
    it('should call onShowVoiceInput when clicked', async () => {
      const user = userEvent.setup()
      const onShowVoiceInput = vi.fn()

      render(
        <Operation
          onSend={vi.fn()}
          speechToTextConfig={{ enabled: true }}
          onShowVoiceInput={onShowVoiceInput}
        />,
      )

      const voiceButton = screen.getByRole('button', { name: 'common.voiceInput.start' })

      await user.click(voiceButton!)

      expect(onShowVoiceInput).toHaveBeenCalledTimes(1)
    })

    it('should disable voice button when readonly is true', async () => {
      const user = userEvent.setup()
      const onShowVoiceInput = vi.fn()

      render(
        <Operation
          onSend={vi.fn()}
          speechToTextConfig={{ enabled: true }}
          onShowVoiceInput={onShowVoiceInput}
          readonly
        />,
      )

      const voiceButton = screen.getByRole('button', { name: 'common.voiceInput.start' })

      expect(voiceButton)!.toBeDisabled()

      await user.click(voiceButton!)

      expect(onShowVoiceInput).not.toHaveBeenCalled()
    })
  })
})
