import { useMemo, useState } from 'react'
import { VirtualBackgroundConfig, VirtualBackgroundType } from '@zocks-communications/client-sdk-js'
import { useZocksStore } from '../../app'
import {
  selectCurrentVirtualBackground,
  selectIsScreenSharing,
  selectLocalParticipant,
  selectScreenSharingParticipant,
  ZocksMediaActions,
  ZocksTranscriptionActions,
} from '../../store'
import { useZocksDispatch } from '../../app/hooks'
import {
  clearCurrentVirtualBackground,
  setCurrentVirtualBackground,
} from '../../store/virtualBackground/virtualBackgroundSlice'
import {
  selectLocalStreamTranscriptionStatus,
  selectDisplayTranscriptions,
  selectCurrentAudioDeviceId,
  selectCurrentVideoDeviceId,
} from '../../store'
import { setDisplayTranscriptions } from '../../store/transcript/transcriptSlice'

export const useRoomControls = (mediaActions: ZocksMediaActions) => {
  const {
    publishAudio,
    publishVideo,
    unPublishAudio,
    unPublishVideo,
    switchActiveDevice,
    publishScreenShare,
    unPublishScreenShare,
  } = mediaActions
  const localParticipant = useZocksStore(selectLocalParticipant)
  const isScreenSharing = useZocksStore(selectIsScreenSharing)
  const screenSharingParticipant = useZocksStore(selectScreenSharingParticipant)
  const currentAudioDeviceId = useZocksStore(selectCurrentAudioDeviceId)
  const currentVideoDeviceId = useZocksStore(selectCurrentVideoDeviceId)
  const isLocalScreenShare = screenSharingParticipant === localParticipant
  const audioIsOn = !!(localParticipant.tracks.audioTracks.length && !localParticipant.tracks.audioTracks[0].isMuted)
  const videoIsOn = !!(localParticipant.tracks.videoTracks.length && !localParticipant.tracks.videoTracks[0].isMuted)

  const toggleAudio = () => {
    const mediaTrackSettings = currentAudioDeviceId ? { deviceId: currentAudioDeviceId } : undefined
    if (audioIsOn) {
      unPublishAudio(mediaTrackSettings)
    } else {
      publishAudio(mediaTrackSettings)
    }
  }

  const toggleVideo = () => {
    const mediaTrackSettings = currentVideoDeviceId ? { deviceId: currentVideoDeviceId } : undefined
    if (videoIsOn) {
      unPublishVideo(mediaTrackSettings)
    } else {
      publishVideo(mediaTrackSettings)
    }
  }

  const toggleScreenShare = () => {
    if (isScreenSharing) {
      unPublishScreenShare()
    } else {
      publishScreenShare()
    }
  }

  const selectAudioDevice = (audioDevice: MediaDeviceInfo) => {
    switchActiveDevice('audioinput', audioDevice.deviceId)
  }
  const selectVideoDevice = (videoDevice: MediaDeviceInfo) => {
    switchActiveDevice('videoinput', videoDevice.deviceId)
  }

  return {
    audioIsOn,
    videoIsOn,
    isScreenSharing,
    isLocalScreenShare,
    currentVideoDeviceId,
    toggleAudio,
    toggleVideo,
    toggleScreenShare,
    selectAudioDevice,
    selectVideoDevice,
  }
}

export const useTranscription = (audioIsOn: boolean, transcriptionActions?: ZocksTranscriptionActions) => {
  const dispatch = useZocksDispatch()

  const localStreamTranscriptionStatus = useZocksStore(selectLocalStreamTranscriptionStatus)
  const displayTranscriptions = useZocksStore(selectDisplayTranscriptions)
  const currentAudioDeviceId = useZocksStore(selectCurrentAudioDeviceId)

  const toggleLocalStreamTranscription = async () => {
    if (!transcriptionActions) {
      return
    }
    const { enableTranscription, disableTranscription, startTranscription, stopTranscription } = transcriptionActions
    const { serviceEnabled } = localStreamTranscriptionStatus
    if (serviceEnabled) {
      await stopTranscription()
      await disableTranscription()
    } else {
      await enableTranscription()
      if (audioIsOn) {
        const constraints = currentAudioDeviceId ? { deviceId: currentAudioDeviceId } : undefined
        await startTranscription(constraints)
      }
    }
  }

  const toggleDisplayTranscription = () => {
    dispatch(setDisplayTranscriptions(!displayTranscriptions))
  }

  return {
    displayTranscriptions,
    localStreamTranscriptionStatus,
    toggleLocalStreamTranscription,
    toggleDisplayTranscription,
  }
}

export const useVirtualBackgrounds = (mediaActions: ZocksMediaActions, config?: VirtualBackgroundConfig) => {
  const dispatch = useZocksDispatch()
  const currentVirtualBackground = useZocksStore(selectCurrentVirtualBackground)
  const currentVideoDeviceId = useZocksStore(selectCurrentVideoDeviceId)
  const availableBackgrounds = useMemo(() => Object.values(VirtualBackgroundType), [])
  const { setVirtualBackground, clearVirtualBackground } = mediaActions
  const [virtualBackgroundIsLoading, setVirtualBackgroundIsLoading] = useState<boolean>(false)

  const changeVirtualBackground = async (virtualBackgroundType: VirtualBackgroundType | null) => {
    setVirtualBackgroundIsLoading(true)
    const mediaTrackSettings = currentVideoDeviceId ? { deviceId: currentVideoDeviceId } : undefined
    if (virtualBackgroundType) {
      try {
        await setVirtualBackground(virtualBackgroundType, config, mediaTrackSettings)
        dispatch(setCurrentVirtualBackground(virtualBackgroundType))
      } finally {
        setVirtualBackgroundIsLoading(false)
      }
    } else {
      try {
        await clearVirtualBackground(mediaTrackSettings)
        dispatch(clearCurrentVirtualBackground())
      } finally {
        setVirtualBackgroundIsLoading(false)
      }
    }
  }

  const toggleBlur = async () => {
    if (currentVirtualBackground) {
      await changeVirtualBackground(null)
    } else {
      await changeVirtualBackground(VirtualBackgroundType.BLUR)
    }
  }

  return {
    availableBackgrounds,
    currentVirtualBackground,
    virtualBackgroundIsLoading,
    toggleBlur,
  }
}
