import React, { useCallback, useEffect, useState } from 'react';
import { Box, Button, color, Icon, Icons, Spinner, Text } from 'folds';
import { SequenceCard } from '../../components/sequence-card';
import * as css from './styles.css';
import { ChatButton, ControlDivider, MicrophoneButton, SoundButton, VideoButton } from './Controls';
import { useIsDirectRoom, useRoom } from '../../hooks/useRoom';
import { useCallEmbed, useCallJoined, useCallStart } from '../../hooks/useCallEmbed';
import { useCallPreferences } from '../../state/hooks/callPreferences';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';

type MediaPermState = 'granted' | 'denied' | 'prompt' | 'unknown';

function useMediaPermissions(): MediaPermState {
  const [state, setState] = useState<MediaPermState>('unknown');

  useEffect(() => {
    if (!navigator.permissions) {
      setState('unknown');
      return undefined;
    }
    let cancelled = false;
    let permStatus: PermissionStatus | undefined;
    navigator.permissions
      .query({ name: 'microphone' as unknown as PermissionDescriptor['name'] })
      .then((result) => {
        if (cancelled) return;
        permStatus = result;
        setState(result.state as MediaPermState);
        result.onchange = () => {
          if (!cancelled) setState(result.state as MediaPermState);
        };
      })
      .catch(() => {
        if (!cancelled) setState('unknown');
      });
    // Detach the onchange handler on unmount so it can't setState afterward (and
    // so the PermissionStatus doesn't retain the callback).
    return () => {
      cancelled = true;
      if (permStatus) permStatus.onchange = null;
    };
  }, []);

  return state;
}

type PrescreenControlsProps = {
  canJoin?: boolean;
};
export function PrescreenControls({ canJoin }: PrescreenControlsProps) {
  const room = useRoom();
  const callEmbed = useCallEmbed();
  const callJoined = useCallJoined(callEmbed);
  const direct = useIsDirectRoom();

  const inOtherCall = callEmbed && callEmbed.roomId !== room.roomId;

  const startCall = useCallStart(direct);
  const joining = callEmbed?.roomId === room.roomId && !callJoined;

  const micPermission = useMediaPermissions();
  const micDenied = micPermission === 'denied';

  const disabled = inOtherCall || !canJoin || micDenied;

  const { microphone, video, sound, toggleMicrophone, toggleVideo, toggleSound } =
    useCallPreferences();
  const [cameraOnJoin] = useSetting(settingsAtom, 'cameraOnJoin');

  const handleMicrophoneToggle = useCallback(async () => toggleMicrophone(), [toggleMicrophone]);
  const handleVideoToggle = useCallback(async () => toggleVideo(), [toggleVideo]);

  return (
    <SequenceCard
      className={css.ControlCard}
      variant="SurfaceVariant"
      gap="400"
      radii="500"
      alignItems="Center"
      justifyContent="SpaceBetween"
      wrap="Wrap"
    >
      <Box shrink="No" alignItems="Inherit" justifyContent="SpaceBetween" gap="200">
        <MicrophoneButton enabled={microphone} onToggle={handleMicrophoneToggle} />
        <SoundButton enabled={sound} onToggle={toggleSound} />
      </Box>
      <ControlDivider />
      <Box shrink="No" alignItems="Inherit" justifyContent="SpaceBetween" gap="200">
        <VideoButton enabled={video} onToggle={handleVideoToggle} disabled={!cameraOnJoin} />
        <ChatButton />
      </Box>
      <Box grow="Yes" direction="Column" gap="200">
        {micDenied && (
          <Text size="T200" style={{ color: color.Critical.Main, textAlign: 'center' }}>
            Microphone access is blocked. Enable it in your browser settings to join.
          </Text>
        )}
        <Button
          variant={disabled ? 'Secondary' : 'Success'}
          fill={disabled ? 'Soft' : 'Solid'}
          onClick={() => startCall(room, { microphone, video, sound })}
          disabled={disabled || joining}
          before={
            joining ? (
              <Spinner variant="Success" fill="Solid" size="200" />
            ) : (
              <Icon src={Icons.Phone} size="200" filled />
            )
          }
        >
          <Text size="B400">Join</Text>
        </Button>
      </Box>
    </SequenceCard>
  );
}
