import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { DefaultAudioControlMenu, TranscriptionAudioControlMenu } from './AudioControlMenu'
import React from 'react'

const transcriptionStatus = {
  serviceEnabled: false,
  autoEnabled: false,
  serviceLoading: false,
  displayTranscriptions: true,
  transcriptionInProgress: false,
}
test('DefaultAudioControlMenu renders an audio control menu with the available input and output devices', () => {
  render(
    <DefaultAudioControlMenu
      menuItems={[
        {
          label: 'Test audio input device 1',
          value: 'testAudioInputDevice1Id',
          kind: 'audioinput',
        },
        {
          label: 'Test audio input device 2',
          value: 'testAudioInputDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
        {
          label: 'Test audio output device 1',
          value: 'testAudioOutputDevice1Id',
          selected: true,
          kind: 'audiooutput',
        },
      ]}
      onMenuItemClick={jest.fn()}
      hideMenu={jest.fn()}
    />
  )

  expect(screen.getByText('Microphone Settings')).toBeInTheDocument()
  expect(screen.getByText('Test audio input device 1')).toBeInTheDocument()
  expect(screen.getByText('Test audio input device 2')).toBeInTheDocument()
  expect(screen.getByText('Test audio output device 1')).toBeInTheDocument()
})

test('DefaultAudioControlMenu calls the onMenuItemClick callback when clicking on an audio device menu item', () => {
  const mockMenuItemClick = jest.fn()
  render(
    <DefaultAudioControlMenu
      menuItems={[
        {
          label: 'Test audio input device 1',
          value: 'testAudioInputDevice1Id',
          kind: 'audioinput',
        },
        {
          label: 'Test audio input device 2',
          value: 'testAudioInputDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
      ]}
      onMenuItemClick={mockMenuItemClick}
      hideMenu={jest.fn()}
    />
  )

  userEvent.click(screen.getByText('Test audio input device 1'))

  expect(mockMenuItemClick).toHaveBeenCalledTimes(1)
  expect(mockMenuItemClick).toHaveBeenCalledWith({
    label: 'Test audio input device 1',
    value: 'testAudioInputDevice1Id',
    kind: 'audioinput',
  })
})

test('TranscriptionAudioControlMenu renders an audio control menu with the available input and output devices and a transcription toggle', () => {
  const TestAudioControlMenu = TranscriptionAudioControlMenu(transcriptionStatus, jest.fn())
  render(
    <TestAudioControlMenu
      menuItems={[
        {
          label: 'Test audio input device 1',
          value: 'testAudioInputDevice1Id',
          kind: 'audioinput',
        },
        {
          label: 'Test audio input device 2',
          value: 'testAudioInputDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
        {
          label: 'Test audio output device 1',
          value: 'testAudioOutputDevice1Id',
          kind: 'audiooutput',
        },
      ]}
      onMenuItemClick={jest.fn()}
      hideMenu={jest.fn()}
    />
  )

  expect(screen.getByText('Microphone Settings')).toBeInTheDocument()
  expect(screen.getByText('Test audio input device 1')).toBeInTheDocument()
  expect(screen.getByText('Test audio input device 2')).toBeInTheDocument()
  expect(screen.getByText('Audio Output Settings')).toBeInTheDocument()
  expect(screen.getByText('Test audio output device 1')).toBeInTheDocument()
  expect(screen.getByText('Enable Transcription')).toBeInTheDocument()
})

test('TranscriptionAudioControlMenu renders an audio control menu with the defaults if there is no input or output devices', () => {
  const TestAudioControlMenu = TranscriptionAudioControlMenu(transcriptionStatus, jest.fn())
  const mockMenuItemClick = jest.fn()
  render(<TestAudioControlMenu menuItems={[]} onMenuItemClick={mockMenuItemClick} hideMenu={jest.fn()} />)

  expect(screen.getByText('Microphone Settings')).toBeInTheDocument()
  expect(screen.getByText('System Default Microphone Device')).toBeInTheDocument()
  expect(screen.getByText('Audio Output Settings')).toBeInTheDocument()
  expect(screen.getByText('System Default Speaker Device')).toBeInTheDocument()
  expect(screen.getByText('Enable Transcription')).toBeInTheDocument()
  userEvent.click(screen.getByText('System Default Speaker Device'))
  expect(mockMenuItemClick).toBeCalledWith(null)
})

test('TranscriptionAudioControlMenu renders the control menu with a disable option when transcription is turned on', () => {
  const TestAudioControlMenu = TranscriptionAudioControlMenu(
    { ...transcriptionStatus, serviceEnabled: true },
    jest.fn()
  )
  render(
    <TestAudioControlMenu
      menuItems={[
        { label: 'Test audio device 1', value: 'testAudioDevice1Id', kind: 'audioinput' },
        {
          label: 'Test audio device 2',
          value: 'testAudioDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
      ]}
      onMenuItemClick={jest.fn()}
      hideMenu={jest.fn()}
    />
  )

  expect(screen.getByText('Microphone Settings')).toBeInTheDocument()
  expect(screen.getByText('Test audio device 1')).toBeInTheDocument()
  expect(screen.getByText('Test audio device 2')).toBeInTheDocument()
  expect(screen.getByText('Disable Transcription')).toBeInTheDocument()
})

test('TranscriptionAudioControlMenu calls the toggleTranscription function when clicking the transcription button', () => {
  const mockToggleTranscription = jest.fn()
  const TestAudioControlMenu = TranscriptionAudioControlMenu(transcriptionStatus, mockToggleTranscription)
  render(
    <TestAudioControlMenu
      menuItems={[
        { label: 'Test audio device 1', value: 'testAudioDevice1Id', kind: 'audioinput' },
        {
          label: 'Test audio device 2',
          value: 'testAudioDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
      ]}
      onMenuItemClick={jest.fn()}
      hideMenu={jest.fn()}
    />
  )

  userEvent.click(screen.getByText('Enable Transcription'))

  expect(mockToggleTranscription).toHaveBeenCalledTimes(1)
})

test('TranscriptionAudioControlMenu displays Show Transcriptions when transcription was automatically enabled and currently transcriptions are not displayed', () => {
  const TestAudioControlMenu = TranscriptionAudioControlMenu(
    { ...transcriptionStatus, serviceEnabled: true, autoEnabled: true, displayTranscriptions: false },
    jest.fn()
  )
  render(
    <TestAudioControlMenu
      menuItems={[
        { label: 'Test audio device 1', value: 'testAudioDevice1Id', kind: 'audioinput' },
        {
          label: 'Test audio device 2',
          value: 'testAudioDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
      ]}
      onMenuItemClick={jest.fn()}
      hideMenu={jest.fn()}
    />
  )

  expect(screen.getByText('Microphone Settings')).toBeInTheDocument()
  expect(screen.getByText('Test audio device 1')).toBeInTheDocument()
  expect(screen.getByText('Test audio device 2')).toBeInTheDocument()
  expect(screen.getByText('Show Transcriptions')).toBeInTheDocument()
})

test('TranscriptionAudioControlMenu displays Hide Transcriptions when transcription was automatically enabled and currently transcriptions are displayed', () => {
  const TestAudioControlMenu = TranscriptionAudioControlMenu(
    { ...transcriptionStatus, serviceEnabled: true, autoEnabled: true, displayTranscriptions: true },
    jest.fn()
  )
  render(
    <TestAudioControlMenu
      menuItems={[
        { label: 'Test audio device 1', value: 'testAudioDevice1Id', kind: 'audioinput' },
        {
          label: 'Test audio device 2',
          value: 'testAudioDevice2Id',
          selected: true,
          kind: 'audioinput',
        },
      ]}
      onMenuItemClick={jest.fn()}
      hideMenu={jest.fn()}
    />
  )

  expect(screen.getByText('Microphone Settings')).toBeInTheDocument()
  expect(screen.getByText('Test audio device 1')).toBeInTheDocument()
  expect(screen.getByText('Test audio device 2')).toBeInTheDocument()
  expect(screen.getByText('Hide Transcriptions')).toBeInTheDocument()
})
