import React, { useCallback, useEffect, useState } from 'react'
import { MediaDeviceManager } from '@zocks-communications/client-sdk-js'
import { DeviceMenuItem, SelectButton } from '../common'
import { useSelectMediaDevice, useSelectMediaDevices } from './hooks'
import { DeviceSelectButtonProps, AudioInputOutputDeviceSelectButtonProps } from './models'

export const DeviceSelectButton: React.FC<DeviceSelectButtonProps> = ({
  deviceKind,
  onDeviceSelected,
  disabled,
  label,
  components,
  styles,
}) => {
  const { selectedMediaDeviceId, selectMediaDevice } = useSelectMediaDevice(deviceKind)
  const [sources, setSources] = useState<MediaDeviceInfo[]>()
  const [menuItems, setMenuItems] = useState<DeviceMenuItem[]>([])

  const SelectMenuElement = components?.SelectMenu

  const listDevices = useCallback(async () => {
    const devices = await MediaDeviceManager.getDevices(deviceKind)
    setSources(devices)
    setMenuItems(
      devices.map((item) => {
        return {
          label: item.label,
          value: item.deviceId,
          selected: item.deviceId === selectedMediaDeviceId,
          disabled: disabled,
          kind: item.kind,
        }
      })
    )
  }, [selectedMediaDeviceId, deviceKind, disabled])

  useEffect(() => {
    if (!sources) {
      return
    }
    if (!sources.length) {
      selectMediaDevice(null)
    } else if (!selectedMediaDeviceId) {
      const defaultDevice = sources[0]
      selectMediaDevice(defaultDevice.deviceId)
    } else if (!sources.some((d) => d.deviceId === selectedMediaDeviceId)) {
      const defaultDevice = sources[0]
      selectMediaDevice(defaultDevice.deviceId)
      onDeviceSelected(defaultDevice)
    }
  }, [selectMediaDevice, selectedMediaDeviceId, sources, deviceKind, onDeviceSelected])

  useEffect(() => {
    listDevices()
    navigator.mediaDevices.addEventListener('devicechange', listDevices)

    return () => {
      navigator.mediaDevices.removeEventListener('devicechange', listDevices)
    }
  }, [listDevices])

  if (!sources || (sources.length <= 1 && !SelectMenuElement)) {
    return <></>
  }

  const onMenuItemSelected = (item: DeviceMenuItem) => {
    const device = sources.find((d) => d.label === item.label)
    if (device) {
      selectMediaDevice(device.deviceId)
      onDeviceSelected(device)
    }
  }

  return (
    <SelectButton
      disabled={disabled}
      styles={styles}
      buttonLabel={label}
      menuItems={menuItems}
      onMenuItemSelected={onMenuItemSelected}
      SelectMenu={SelectMenuElement}
    />
  )
}
export const AudioInputOutputDeviceSelectButton: React.FC<AudioInputOutputDeviceSelectButtonProps> = ({
  onDeviceSelected,
  inputDisabled,
  label,
  components,
  styles,
}) => {
  const {
    selectMediaDevice: selectAudioMediaDevice,
    selectedMediaDeviceId: selectedAudioMediaDeviceId,
    sources: audioInputSources,
  } = useSelectMediaDevices('audioinput', onDeviceSelected)
  const {
    selectMediaDevice: selectAudioOutputMediaDevice,
    selectedMediaDeviceId: selectedAudioOutputMediaDeviceId,
    sources: audioOutputSources,
  } = useSelectMediaDevices('audiooutput', onDeviceSelected)

  const [menuItems, setMenuItems] = useState<DeviceMenuItem[]>([])

  useEffect(() => {
    const deviceMenuItems: DeviceMenuItem[] = []
    audioInputSources?.forEach((source) => {
      deviceMenuItems.push({
        label: source.label,
        value: source.deviceId,
        selected: source.deviceId === selectedAudioMediaDeviceId,
        disabled: inputDisabled,
        kind: source.kind,
      })
    })
    audioOutputSources?.forEach((source) => {
      deviceMenuItems.push({
        label: source.label,
        value: source.deviceId,
        selected: source.deviceId === selectedAudioOutputMediaDeviceId,
        kind: source.kind,
      })
    })
    setMenuItems(deviceMenuItems)
  }, [
    audioInputSources,
    audioOutputSources,
    inputDisabled,
    selectedAudioOutputMediaDeviceId,
    selectedAudioMediaDeviceId,
  ])

  const SelectMenuElement = components?.SelectMenu

  if (!menuItems || (menuItems.length <= 1 && !SelectMenuElement)) {
    return <></>
  }

  const onMenuItemSelected = (item: DeviceMenuItem) => {
    if (item.kind === 'audioinput') {
      const audioInputDevice = audioInputSources?.find((d) => d.label === item.label)
      if (audioInputDevice) {
        selectAudioMediaDevice(audioInputDevice.deviceId)
        onDeviceSelected(audioInputDevice)
      }
    }
    if (item.kind === 'audiooutput') {
      const audioOutputDevice = audioOutputSources?.find((d) => d.label === item.label)
      if (audioOutputDevice) {
        selectAudioOutputMediaDevice(audioOutputDevice.deviceId)
        onDeviceSelected(audioOutputDevice)
      }
    }
  }

  return (
    <SelectButton
      disabled={false}
      styles={styles}
      buttonLabel={label}
      menuItems={menuItems}
      onMenuItemSelected={onMenuItemSelected}
      SelectMenu={SelectMenuElement}
    />
  )
}
