import React, { useState, useEffect, useCallback } from 'react';
import { getAudioContext, initializeAudioOutput } from '@strudel.cycles/webaudio';
import { SelectInput } from './SelectInput';

const initdevices = new Map();
export function AudioDeviceSelector({ audioDeviceName, onChange }) {
  const [devices, setDevices] = useState(initdevices);
  const devicesInitialized = devices.size > 0;

  const setAudioDevice = useCallback(async (id) => {
    const audioCtx = getAudioContext();
    await audioCtx.setSinkId(id);
    initializeAudioOutput();
  });
  const initializedevices = useCallback(async () => {
    await navigator.mediaDevices.getUserMedia({ audio: true });
    let mediaDevices = await navigator.mediaDevices.enumerateDevices();
    mediaDevices = mediaDevices.filter((device) => device.kind === 'audiooutput' && device.deviceId !== 'default');
    const devicesMap = new Map();
    mediaDevices.forEach((device) => {
      devicesMap.set(device.label, device.deviceId);
    });
    setDevices(devicesMap);
    return devicesMap;
  }, []);

  useEffect(() => {
    if (!audioDeviceName.length || devicesInitialized) {
      return;
    }
    initializedevices().then((devices) => {
      const deviceID = devices.get(audioDeviceName);
      if (deviceID == null) {
        onChange('');
        return;
      }
      setAudioDevice(deviceID);
    });
  }, []);

  const onClick = () => {
    if (devicesInitialized) {
      return;
    }
    initializedevices();
  };
  const onDeviceChange = (deviceName) => {
    if (!devicesInitialized) {
      return;
    }
    const deviceID = devices.get(deviceName);
    onChange(deviceName);
    deviceID && setAudioDevice(deviceID);
  };
  const options = new Set();

  Array.from(devices.keys()).forEach((deviceName) => {
    options.add({ id: deviceName, label: deviceName });
  });
  return <SelectInput options={options} onClick={onClick} value={audioDeviceName} onChange={onDeviceChange} />;
}
