import React from 'react'
import userEvent from '@testing-library/user-event'
import { act } from 'react-dom/test-utils'
import { render, screen } from '@testing-library/react'
import { Provider } from 'react-redux'
import { activeSpeakersChanged, participantLocalTrackPublished } from '../../../store/session/sessionSlice'
import { initStore } from '../../../testUtils'
import { StreamKind, StreamSource } from '@zocks-communications/client-sdk-js'
import { ParticipantsScreenShareView } from './ParticipantsScreenShareView'

const mockActiveSpeakers = ['Participant id: 2', 'Participant id: local']

const renderWithScreenShare = (numberOfRemoteParticipants: number, pageSize?: number) => {
  const store = initStore(numberOfRemoteParticipants)
  store.dispatch(
    participantLocalTrackPublished({
      trackId: 'testLocalScreenShareTrackId',
      trackSource: StreamSource.SCREEN_SHARE,
      trackKind: StreamKind.VIDEO,
      trackIsMuted: false,
    })
  )
  store.dispatch(activeSpeakersChanged(mockActiveSpeakers))
  const { container } = render(
    <Provider store={store}>
      <ParticipantsScreenShareView pageSize={pageSize} />
    </Provider>
  )
  return { container, store }
}

test('displays the screen share and participants when there are 4 participants, sorted by the speakers', () => {
  const { container } = renderWithScreenShare(3)

  expect(screen.getByText('Participant name: local')).toBeInTheDocument()
  for (const i of [0, 1, 2]) {
    expect(screen.getByText(`Participant name: ${i}`)).toBeInTheDocument()
  }
  expect(screen.queryByRole('button', { name: 'Previous' })).not.toBeInTheDocument()
  expect(screen.queryByRole('button', { name: 'Next' })).not.toBeInTheDocument()

  const screenShare = container.querySelector('.zocks__screen-share')
  const participants = container.querySelector('.zocks__participants-screen-share-view__participants')
  expect(screenShare).toBeInTheDocument()
  expect(participants!.children[0]).toHaveTextContent('Participant name: local')
  expect(participants!.children[1]).toHaveTextContent('Participant name: 2')
  expect(participants!.children[2]).toHaveTextContent('Participant name: 0')
  expect(participants!.children[3]).toHaveTextContent('Participant name: 1')
})

test('clicking the Next button displays the participants on the next page', () => {
  renderWithScreenShare(4)

  const nextButton = screen.getByRole('button', { name: 'Next' })
  expect(nextButton).not.toBeDisabled()

  userEvent.click(nextButton)

  expect(screen.queryByRole('button', { name: 'Next' })).not.toBeInTheDocument()
  expect(screen.getByText('Participant name: 3')).toBeInTheDocument()
  for (const i of [0, 1, 2]) {
    expect(screen.queryByText(`Participant name: ${i}`)).not.toBeInTheDocument()
  }
  expect(screen.queryByText('Participant name: local')).not.toBeInTheDocument()
})

test('clicking the Previous button displays the participants on the previous page', () => {
  renderWithScreenShare(4)
  userEvent.click(screen.getByRole('button', { name: 'Next' }))

  const previousButton = screen.getByRole('button', { name: 'Previous' })
  expect(previousButton).not.toBeDisabled()
  userEvent.click(previousButton)

  expect(screen.queryByRole('button', { name: 'Previous' })).not.toBeInTheDocument()
  for (const i of [0, 1, 2]) {
    expect(screen.getByText(`Participant name: ${i}`)).toBeInTheDocument()
  }
  expect(screen.getByText('Participant name: local')).toBeInTheDocument()
  expect(screen.queryByText('Participant name: 3')).not.toBeInTheDocument()
})

test('page size is considered when displaying participants', () => {
  renderWithScreenShare(4, 2)

  expect(screen.getAllByText(/Participant name:/)).toHaveLength(2)
  expect(screen.getByText('Participant name: 2')).toBeInTheDocument()
  expect(screen.getByText('Participant name: local')).toBeInTheDocument()
})

test('if a speaker becomes inactive, they are still considered for the ordering of the participants', () => {
  const { container, store } = renderWithScreenShare(3)

  act(() => {
    store.dispatch(activeSpeakersChanged(['Participant id: local']))
  })

  const participants = container.querySelector('.zocks__participants-screen-share-view__participants')
  expect(participants!.children[0]).toHaveTextContent('Participant name: local')
  expect(participants!.children[1]).toHaveTextContent('Participant name: 2')
  expect(participants!.children[2]).toHaveTextContent('Participant name: 0')
  expect(participants!.children[3]).toHaveTextContent('Participant name: 1')
})

test('renders a custom participant element if a custom element is given', () => {
  const store = initStore(1)
  const ParticipantElement = () => <div>custom participant element</div>
  render(
    <Provider store={store}>
      <ParticipantsScreenShareView components={{ Participant: ParticipantElement }} />
    </Provider>
  )

  expect(screen.getAllByText('custom participant element')).toHaveLength(2)
})

test('renders a custom screen share element if a custom element is given', () => {
  const store = initStore(1)
  store.dispatch(
    participantLocalTrackPublished({
      trackId: 'testLocalScreenShareTrackId',
      trackSource: StreamSource.SCREEN_SHARE,
      trackKind: StreamKind.VIDEO,
      trackIsMuted: false,
    })
  )
  const ScreenShareElement = () => <div>custom screen share element</div>
  render(
    <Provider store={store}>
      <ParticipantsScreenShareView components={{ ScreenShare: ScreenShareElement }} />
    </Provider>
  )

  expect(screen.getByText('custom screen share element')).toBeInTheDocument()
})
