import {
  Restricted,
  useCallStateHooks,
  useI18n,
  UseInputMediaDeviceOptions,
} from '@stream-io/video-react-bindings';
import clsx from 'clsx';
import { OwnCapability, SfuModels } from '@stream-io/video-client';
import { CompositeButton, IconButtonWithMenuProps } from '../Button/';
import { DeviceSelectorVideo } from '../DeviceSettings';
import { PermissionNotification } from '../Notification';
import { useRequestPermission } from '../../hooks';
import { Icon } from '../Icon';
import { WithTooltip } from '../Tooltip';
import { useState } from 'react';
import {
  createCallControlHandler,
  PropsWithErrorHandler,
} from '../../utilities/callControlHandler';

export type ToggleVideoPreviewButtonProps = PropsWithErrorHandler<
  Pick<
    IconButtonWithMenuProps,
    'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
  > &
    UseInputMediaDeviceOptions
>;

export const ToggleVideoPreviewButton = (
  props: ToggleVideoPreviewButtonProps,
) => {
  const {
    caption,
    Menu = DeviceSelectorVideo,
    menuPlacement = 'top',
    onMenuToggle,
    optimisticUpdates,
    ...restCompositeButtonProps
  } = props;
  const { t } = useI18n();
  const { useCameraState, useLocalParticipant } = useCallStateHooks();
  const {
    camera,
    hasBrowserPermission,
    isPromptingPermission,
    isTogglePending,
    optionsAwareIsMute,
  } = useCameraState({ optimisticUpdates });
  const localParticipant = useLocalParticipant();
  const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(
    SfuModels.TrackType.VIDEO,
  );
  const [tooltipDisabled, setTooltipDisabled] = useState(false);
  const handleClick = createCallControlHandler(props, () => camera.toggle());

  return (
    <WithTooltip
      title={
        !hasBrowserPermission
          ? t('Check your browser video permissions')
          : isSystemMuted
            ? t('Camera is paused by your system')
            : (caption ?? t('Video'))
      }
      tooltipDisabled={tooltipDisabled}
    >
      <CompositeButton
        active={optionsAwareIsMute}
        caption={caption}
        className={clsx(
          !hasBrowserPermission && 'str-video__device-unavailable',
        )}
        variant="secondary"
        data-testid={
          optionsAwareIsMute
            ? 'preview-video-unmute-button'
            : 'preview-video-mute-button'
        }
        onClick={handleClick}
        disabled={
          !hasBrowserPermission || (!optimisticUpdates && isTogglePending)
        }
        Menu={Menu}
        menuPlacement={menuPlacement}
        {...restCompositeButtonProps}
        onMenuToggle={(shown) => {
          setTooltipDisabled(shown);
          onMenuToggle?.(shown);
        }}
      >
        <Icon icon={!optionsAwareIsMute ? 'camera' : 'camera-off'} />
        {!hasBrowserPermission && (
          <span
            className="str-video__no-media-permission"
            title={t('Check your browser video permissions')}
            children="!"
          />
        )}
        {isPromptingPermission && (
          <span
            className="str-video__pending-permission"
            title={t('Waiting for permission')}
            children="?"
          />
        )}
        {isSystemMuted && hasBrowserPermission && (
          <span
            className="str-video__system-muted"
            title={t('Camera is paused by your system')}
            children="!"
          />
        )}
      </CompositeButton>
    </WithTooltip>
  );
};

type ToggleVideoPublishingButtonProps = PropsWithErrorHandler<
  Pick<
    IconButtonWithMenuProps,
    'caption' | 'Menu' | 'menuPlacement' | 'onMenuToggle'
  > &
    UseInputMediaDeviceOptions
>;

export const ToggleVideoPublishingButton = (
  props: ToggleVideoPublishingButtonProps,
) => {
  const { t } = useI18n();
  const {
    caption,
    Menu = <DeviceSelectorVideo visualType="list" />,
    menuPlacement = 'top',
    onMenuToggle,
    optimisticUpdates,
    ...restCompositeButtonProps
  } = props;

  const { hasPermission, requestPermission, isAwaitingPermission } =
    useRequestPermission(OwnCapability.SEND_VIDEO);

  const { useCameraState, useCallSettings, useLocalParticipant } =
    useCallStateHooks();
  const {
    camera,
    optionsAwareIsMute,
    hasBrowserPermission,
    isPromptingPermission,
    isTogglePending,
  } = useCameraState({ optimisticUpdates });
  const localParticipant = useLocalParticipant();
  const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(
    SfuModels.TrackType.VIDEO,
  );
  const callSettings = useCallSettings();
  const isPublishingVideoAllowed = callSettings?.video.enabled;
  const [tooltipDisabled, setTooltipDisabled] = useState(false);
  const handleClick = createCallControlHandler(props, async () => {
    if (!hasPermission) {
      await requestPermission();
    } else {
      await camera.toggle();
    }
  });

  return (
    <Restricted requiredGrants={[OwnCapability.SEND_VIDEO]}>
      <PermissionNotification
        permission={OwnCapability.SEND_VIDEO}
        isAwaitingApproval={isAwaitingPermission}
        messageApproved={t('You can now share your video.')}
        messageAwaitingApproval={t(
          'Awaiting for an approval to share your video.',
        )}
        messageRevoked={t('You can no longer share your video.')}
      >
        <WithTooltip
          title={
            !hasPermission
              ? t('You have no permission to share your video')
              : !hasBrowserPermission
                ? t('Check your browser video permissions')
                : !isPublishingVideoAllowed
                  ? t('Video publishing is disabled by the system')
                  : isSystemMuted
                    ? t('Camera is paused by your system')
                    : caption || t('Video')
          }
          tooltipDisabled={tooltipDisabled}
        >
          <CompositeButton
            active={optionsAwareIsMute}
            caption={caption}
            variant="secondary"
            disabled={
              !hasBrowserPermission ||
              !hasPermission ||
              !isPublishingVideoAllowed ||
              (!optimisticUpdates && isTogglePending)
            }
            data-testid={
              optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button'
            }
            onClick={handleClick}
            Menu={Menu}
            menuPlacement={menuPlacement}
            menuOffset={16}
            {...restCompositeButtonProps}
            onMenuToggle={(shown) => {
              setTooltipDisabled(shown);
              onMenuToggle?.(shown);
            }}
          >
            <Icon icon={optionsAwareIsMute ? 'camera-off' : 'camera'} />
            {(!hasBrowserPermission ||
              !hasPermission ||
              !isPublishingVideoAllowed) && (
              <span className="str-video__no-media-permission">!</span>
            )}
            {isPromptingPermission && (
              <span
                className="str-video__pending-permission"
                title={t('Waiting for permission')}
              >
                ?
              </span>
            )}
            {isSystemMuted &&
              hasBrowserPermission &&
              hasPermission &&
              isPublishingVideoAllowed && (
                <span
                  className="str-video__system-muted"
                  title={t('Camera is paused by your system')}
                >
                  !
                </span>
              )}
          </CompositeButton>
        </WithTooltip>
      </PermissionNotification>
    </Restricted>
  );
};
