import React, { ComponentType, useEffect, useState } from 'react'
import classNames from 'classnames'
import { Participant, ParticipantProps } from '../../Participant'
import { useZocksStore } from '../../../app'
import { ParticipantModel, selectLocalParticipant } from '../../../store'
import { usePagedParticipants, useSortRemoteParticipantsBySpeakers } from '../hooks'
import { MultipleParticipantViewProps } from '../model'
import zocksStyle from './ParticipantsSpeakerView.module.scss'
import { getClassName, getMergedClassNames } from '../../common'
import { StyledComponent } from '../../common'

export const ParticipantsSpeakerView: React.FC<MultipleParticipantViewProps> = ({
  pageSize = 4,
  components,
  styles,
}) => {
  const localParticipant = useZocksStore(selectLocalParticipant)

  const { remoteParticipantsSortedBySpeakers } = useSortRemoteParticipantsBySpeakers()
  const remoteParticipantsExist = !!remoteParticipantsSortedBySpeakers.length

  const mainParticipant = remoteParticipantsExist ? remoteParticipantsSortedBySpeakers[0] : localParticipant
  const allParticipants = [localParticipant, ...remoteParticipantsSortedBySpeakers]
  const { displayedParticipants, hasNextPage, hasPreviousPage, nextPage, previousPage } = usePagedParticipants(
    allParticipants,
    pageSize
  )

  const ParticipantElement = components?.Participant ?? Participant
  const mergedStyles = getMergedClassNames(zocksStyle, styles)
  return (
    <div className={getClassName('participants-speaker-view', mergedStyles)}>
      <div
        className={classNames(getClassName('participants-speaker-view__active-speaker', mergedStyles), {
          [getClassName('participants-speaker-view__only-speaker', mergedStyles)]: !remoteParticipantsExist,
        })}
      >
        {mainParticipant && (
          <ActiveSpeakerParticipant
            mainParticipant={mainParticipant}
            components={{ Participant: ParticipantElement }}
            styles={mergedStyles}
          />
        )}
      </div>
      {remoteParticipantsExist && (
        <>
          {hasPreviousPage && <PreviousButton onClick={previousPage} styles={mergedStyles} />}
          <div className={getClassName('participants-speaker-view__others-container', mergedStyles)}>
            <div className={getClassName('participants-speaker-view__others', mergedStyles)}>
              {displayedParticipants.map((participant) => (
                <ParticipantElement key={participant.id} participant={participant} styles={mergedStyles} />
              ))}
            </div>
          </div>
          {hasNextPage && <NextButton onClick={nextPage} styles={mergedStyles} />}
        </>
      )}
    </div>
  )
}

export const ActiveSpeakerParticipant: React.FC<
  {
    mainParticipant: ParticipantModel
    components?: {
      Participant?: ComponentType<ParticipantProps>
    }
  } & StyledComponent
> = ({ mainParticipant, components, styles }) => {
  const SPEAKER_CHANGE_DELAY = 1000

  const [participant1, setParticipant1] = useState<ParticipantModel>(mainParticipant)
  const [participant2, setParticipant2] = useState<ParticipantModel>(mainParticipant)
  const [showParticipant1, setShowParticipant1] = useState<boolean>(true)

  const displayedParticipantId = showParticipant1 ? participant1.id : participant2.id

  useEffect(() => {
    if (mainParticipant.id !== displayedParticipantId) {
      const timeout = setTimeout(() => setShowParticipant1((showP1) => !showP1), SPEAKER_CHANGE_DELAY)
      return () => clearTimeout(timeout)
    }
  }, [displayedParticipantId, mainParticipant])

  useEffect(() => {
    if (showParticipant1) {
      if (mainParticipant.id !== displayedParticipantId) {
        setParticipant2(mainParticipant)
      } else {
        setParticipant1(mainParticipant)
      }
    } else {
      if (mainParticipant.id !== displayedParticipantId) {
        setParticipant1(mainParticipant)
      } else {
        setParticipant2(mainParticipant)
      }
    }
  }, [displayedParticipantId, showParticipant1, mainParticipant])

  const ParticipantElement = components?.Participant ?? Participant

  return (
    <div className={getClassName('active-speaker__container', styles)}>
      <div
        className={classNames(getClassName('active-speaker__participant', styles), {
          [getClassName('active-speaker__participant--hidden', styles)]: !showParticipant1,
        })}
        data-testid='participant1Element'
      >
        <ParticipantElement participant={participant1} styles={styles} />
      </div>
      <div
        className={classNames(getClassName('active-speaker__participant', styles), {
          [getClassName('active-speaker__participant--hidden', styles)]: showParticipant1,
        })}
        data-testid='participant2Element'
      >
        <ParticipantElement participant={participant2} styles={styles} />
      </div>
    </div>
  )
}

const PreviousButton: React.FC<{ onClick: () => void } & StyledComponent> = ({ onClick, styles }) => (
  <button
    className={`${getClassName('participants-speaker-view__button', styles)} ${getClassName(
      'participants-speaker-view__previous-button',
      styles
    )}`}
    onClick={onClick}
    aria-label='Previous'
  >
    <div className={getClassName('participants-speaker-view__previous-button-icon', styles)} />
  </button>
)

const NextButton: React.FC<{ onClick: () => void } & StyledComponent> = ({ onClick, styles }) => (
  <button
    className={`${getClassName('participants-speaker-view__button', styles)} ${getClassName(
      'participants-speaker-view__next-button',
      styles
    )}`}
    onClick={onClick}
    aria-label='Next'
  >
    <div className={getClassName('participants-speaker-view__next-button-icon', styles)} />
  </button>
)
