import { Box, Chip, Icon, IconButton, Icons, Spinner, Text, Tooltip, TooltipProvider } from 'folds';
import React, { useCallback } from 'react';
import { useSetAtom, useStore } from 'jotai';
import { useTranslation } from 'react-i18next';
import { StatusDivider } from './components';
import { CallEmbed, useCallControlState } from '../../plugins/call';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { callEmbedAtom } from '../../state/callEmbed';

// Fail-open window for widget hangup ack. If the widget is healthy, its
// im.vector.hangup / io.element.close action lands within a second and
// clearIfCurrent (CallEmbedProvider) drops the atom. If LiveKit is dead and
// the widget never replies, we fall through and force-clear locally — same
// pattern as element-web's performDisconnection TIMEOUT_MS (16s there, 8s
// here to match the mobile-ish feel of our DM flow and PEER_LEAVE_GRACE_MS).
const HANGUP_TIMEOUT_MS = 8000;

type MicrophoneButtonProps = {
  enabled: boolean;
  onToggle: () => Promise<unknown>;
  disabled?: boolean;
};
function MicrophoneButton({ enabled, onToggle, disabled }: MicrophoneButtonProps) {
  const { t } = useTranslation();
  return (
    <TooltipProvider
      position="Top"
      tooltip={
        <Tooltip>
          <Text size="T200">{enabled ? t('Call.mic_off') : t('Call.mic_on')}</Text>
        </Tooltip>
      }
    >
      {(anchorRef) => (
        <IconButton
          ref={anchorRef}
          variant={enabled ? 'Surface' : 'Warning'}
          fill="Soft"
          radii="300"
          size="300"
          onClick={() => onToggle()}
          outlined
          disabled={disabled}
        >
          <Icon size="100" src={enabled ? Icons.Mic : Icons.MicMute} filled={!enabled} />
        </IconButton>
      )}
    </TooltipProvider>
  );
}

type SoundButtonProps = {
  enabled: boolean;
  onToggle: () => void;
  disabled?: boolean;
};
function SoundButton({ enabled, onToggle, disabled }: SoundButtonProps) {
  const { t } = useTranslation();
  return (
    <TooltipProvider
      position="Top"
      tooltip={
        <Tooltip>
          <Text size="T200">{enabled ? t('Call.sound_off') : t('Call.sound_on')}</Text>
        </Tooltip>
      }
    >
      {(anchorRef) => (
        <IconButton
          ref={anchorRef}
          variant={enabled ? 'Surface' : 'Warning'}
          fill="Soft"
          radii="300"
          size="300"
          onClick={() => onToggle()}
          outlined
          disabled={disabled}
        >
          <Icon
            size="100"
            src={enabled ? Icons.Headphone : Icons.HeadphoneMute}
            filled={!enabled}
          />
        </IconButton>
      )}
    </TooltipProvider>
  );
}

type VideoButtonProps = {
  enabled: boolean;
  onToggle: () => Promise<unknown>;
  disabled?: boolean;
};
function VideoButton({ enabled, onToggle, disabled }: VideoButtonProps) {
  const { t } = useTranslation();
  return (
    <TooltipProvider
      position="Top"
      tooltip={
        <Tooltip>
          <Text size="T200">{enabled ? t('Call.camera_off') : t('Call.camera_on')}</Text>
        </Tooltip>
      }
    >
      {(anchorRef) => (
        <IconButton
          ref={anchorRef}
          variant={enabled ? 'Success' : 'Surface'}
          fill="Soft"
          radii="300"
          size="300"
          onClick={() => onToggle()}
          outlined
          disabled={disabled}
        >
          <Icon
            size="100"
            src={enabled ? Icons.VideoCamera : Icons.VideoCameraMute}
            filled={enabled}
          />
        </IconButton>
      )}
    </TooltipProvider>
  );
}

type ScreenShareButtonProps = {
  enabled: boolean;
  onToggle: () => void;
  disabled?: boolean;
};
function ScreenShareButton({ enabled, onToggle, disabled }: ScreenShareButtonProps) {
  const { t } = useTranslation();
  return (
    <TooltipProvider
      position="Top"
      tooltip={
        <Tooltip>
          <Text size="T200">{enabled ? t('Call.screenshare_off') : t('Call.screenshare_on')}</Text>
        </Tooltip>
      }
    >
      {(anchorRef) => (
        <IconButton
          ref={anchorRef}
          variant={enabled ? 'Success' : 'Surface'}
          fill="Soft"
          radii="300"
          size="300"
          onClick={onToggle}
          outlined
          disabled={disabled}
        >
          <Icon size="100" src={Icons.ScreenShare} filled={enabled} />
        </IconButton>
      )}
    </TooltipProvider>
  );
}

export function CallControl({
  callEmbed,
  compact,
  callJoined,
}: {
  callEmbed: CallEmbed;
  compact: boolean;
  callJoined: boolean;
}) {
  const { t } = useTranslation();
  const { microphone, video, sound, screenshare } = useCallControlState(callEmbed.control);
  const setCallEmbed = useSetAtom(callEmbedAtom);
  const store = useStore();

  const [hangupState, hangup] = useAsyncCallback(
    useCallback(async () => {
      // Transport.send itself can reject (widget dead / unsupported action).
      // Swallow and still poll — even a dead widget may later re-emit via the
      // Close path, and the force-clear fallback guarantees forward progress.
      try {
        await callEmbed.hangup();
      } catch {
        /* noop — fall through to poll + force-clear */
      }
      const start = Date.now();
      while (Date.now() - start < HANGUP_TIMEOUT_MS) {
        if (store.get(callEmbedAtom) !== callEmbed) return;
        // eslint-disable-next-line no-await-in-loop
        await new Promise((r) => {
          setTimeout(r, 200);
        });
      }
      if (store.get(callEmbedAtom) === callEmbed) {
        setCallEmbed(undefined);
      }
    }, [callEmbed, store, setCallEmbed])
  );
  const exiting =
    hangupState.status === AsyncStatus.Loading || hangupState.status === AsyncStatus.Success;

  const handleHangup = () => {
    if (!callJoined) {
      setCallEmbed(undefined);
      return;
    }
    hangup();
  };

  return (
    <Box shrink="No" alignItems="Center" gap="300">
      <Box alignItems="Inherit" gap="200">
        <MicrophoneButton
          enabled={microphone}
          onToggle={() => callEmbed.control.toggleMicrophone()}
          disabled={!callJoined}
        />
        <SoundButton
          enabled={sound}
          onToggle={() => callEmbed.control.toggleSound()}
          disabled={!callJoined}
        />
        {!callEmbed.voiceOnly && (
          <>
            {!compact && <StatusDivider />}
            <VideoButton
              enabled={video}
              onToggle={() => callEmbed.control.toggleVideo()}
              disabled={!callJoined}
            />
            {!compact && (
              <ScreenShareButton
                enabled={screenshare}
                onToggle={() => callEmbed.control.toggleScreenshare()}
                disabled={!callJoined}
              />
            )}
          </>
        )}
      </Box>
      <StatusDivider />
      <Chip
        variant="Critical"
        radii="Pill"
        fill="Soft"
        before={
          exiting ? (
            <Spinner variant="Critical" fill="Soft" size="50" />
          ) : (
            <Icon size="50" src={Icons.PhoneDown} filled />
          )
        }
        disabled={exiting}
        outlined
        onClick={handleHangup}
      >
        {!compact && (
          <Text as="span" size="L400">
            {t('Call.end_call')}
          </Text>
        )}
      </Chip>
    </Box>
  );
}
