import React, { MouseEventHandler, useCallback, useEffect, useRef, useState } from 'react';
import {
  Box,
  Button,
  Chip,
  config,
  Icon,
  IconButton,
  Icons,
  Menu,
  MenuItem,
  PopOut,
  RectCords,
  Spinner,
  Text,
  toRem,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { SequenceCard } from '../../components/sequence-card';
import * as css from './styles.css';
import {
  ChatButton,
  ControlDivider,
  MicrophoneButton,
  ScreenShareButton,
  SoundButton,
  VideoButton,
} from './Controls';
import { CallEmbed, useCallControlState } from '../../plugins/call';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { useResizeObserver } from '../../hooks/useResizeObserver';
import { stopPropagation } from '../../utils/keyboard';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';

type CallControlsProps = {
  callEmbed: CallEmbed;
};
export function CallControls({ callEmbed }: CallControlsProps) {
  const controlRef = useRef<HTMLDivElement>(null);
  const [compact, setCompact] = useState(document.body.clientWidth < 500);

  useResizeObserver(
    useCallback(() => {
      const element = controlRef.current;
      if (!element) return;
      setCompact(element.clientWidth < 500);
    }, []),
    useCallback(() => controlRef.current, [])
  );

  const { microphone, video, sound, screenshare, spotlight } = useCallControlState(
    callEmbed.control
  );

  const [cords, setCords] = useState<RectCords>();
  const [shareConfirm, setShareConfirm] = useState(false);
  const [pttMode] = useSetting(settingsAtom, 'pttMode');
  const [pttKey] = useSetting(settingsAtom, 'pttKey');
  const [lotusTerminal] = useSetting(settingsAtom, 'lotusTerminal');
  const [pttActive, setPttActive] = useState(false);

  // Track microphone via ref so the PTT effect doesn't need it as a dep (avoids listener churn)
  const microphoneRef = useRef(microphone);
  useEffect(() => { microphoneRef.current = microphone; }, [microphone]);

  // Handle PTT mode toggle mid-call
  const pttModeRef = useRef(pttMode);
  useEffect(() => {
    if (pttMode && !pttModeRef.current) {
      callEmbed.control.setMicrophone(false);
    } else if (!pttMode && pttModeRef.current) {
      callEmbed.control.setMicrophone(true);
    }
    pttModeRef.current = pttMode;
  }, [pttMode, callEmbed]);

  const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
    setCords(evt.currentTarget.getBoundingClientRect());
  };

  const handleSpotlightClick = () => {
    callEmbed.control.toggleSpotlight();
    setCords(undefined);
  };

  const handleReactionsClick = () => {
    callEmbed.control.toggleReactions();
    setCords(undefined);
  };

  const handleSettingsClick = () => {
    callEmbed.control.toggleSettings();
    setCords(undefined);
  };

  useEffect(() => {
    if (!pttMode) return;
    const iframeWindow = callEmbed.iframe.contentWindow;

    const onKeyDown = (e: KeyboardEvent) => {
      if (e.code !== pttKey || e.repeat) return;
      // Don't intercept keys typed into a text input or editable element
      const target = e.target as HTMLElement;
      // Skip PTT if key is pressed inside any text-input or editable surface
      const isEditable = (el: HTMLElement): boolean => {
        const tag = el.tagName;
        if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;
        let node: HTMLElement | null = el;
        while (node && node !== document.body) {
          if (node.contentEditable === 'true') return true;
          if (node.contentEditable === 'false') return false;
          node = node.parentElement;
        }
        return false;
      };
      if (isEditable(target)) return;
      e.preventDefault();
      if (!microphoneRef.current) callEmbed.control.setMicrophone(true);
      setPttActive(true);
    };
    const onKeyUp = (e: KeyboardEvent) => {
      if (e.code !== pttKey) return;
      callEmbed.control.setMicrophone(false);
      setPttActive(false);
    };
    // Release PTT when the tab loses focus to prevent stuck-on mic
    const onBlur = () => {
      callEmbed.control.setMicrophone(false);
      setPttActive(false);
    };
    // Re-mute on focus restore: EC can re-assert audio_enabled:true on audio-context resume
    const onFocus = () => {
      callEmbed.control.setMicrophone(false);
      setPttActive(false);
    };
    window.addEventListener('keydown', onKeyDown);
    window.addEventListener('keyup', onKeyUp);
    window.addEventListener('blur', onBlur);
    window.addEventListener('focus', onFocus);
    iframeWindow?.addEventListener('keydown', onKeyDown);
    iframeWindow?.addEventListener('keyup', onKeyUp);
    return () => {
      window.removeEventListener('keydown', onKeyDown);
      window.removeEventListener('keyup', onKeyUp);
      window.removeEventListener('blur', onBlur);
      window.removeEventListener('focus', onFocus);
      iframeWindow?.removeEventListener('keydown', onKeyDown);
      iframeWindow?.removeEventListener('keyup', onKeyUp);
    };
  // microphone intentionally read via microphoneRef — excluded from deps to avoid listener churn
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pttMode, pttKey, callEmbed]);

  const [hangupState, hangup] = useAsyncCallback(
    useCallback(() => callEmbed.hangup(), [callEmbed])
  );
  const exiting =
    hangupState.status === AsyncStatus.Loading || hangupState.status === AsyncStatus.Success;

  const pttKeyLabel = pttKey === 'Space' ? 'SPACE' : pttKey.replace('Key', '').replace('Digit', '');

  return (
    <Box
      ref={controlRef}
      className={css.CallControlContainer}
      justifyContent="Center"
      alignItems="Center"
    >
      {pttMode && (
        lotusTerminal ? (
          <Box style={{
            position: 'absolute',
            top: '-2.5rem',
            left: '50%',
            transform: 'translateX(-50%)',
            background: pttActive ? 'rgba(0,255,136,0.18)' : 'rgba(255,107,0,0.12)',
            border: `1px solid ${pttActive ? 'rgba(0,255,136,0.55)' : 'rgba(255,107,0,0.35)'}`,
            borderRadius: '99px',
            padding: '0.2rem 0.9rem',
            pointerEvents: 'none',
            whiteSpace: 'nowrap',
          }}>
            <Text size="T200" style={{ color: pttActive ? '#00FF88' : '#FF6B00', fontWeight: 700, letterSpacing: '0.08em', fontFamily: 'JetBrains Mono, monospace' }}>
              {pttActive ? '● LIVE' : `PTT — Hold ${pttKeyLabel}`}
            </Text>
          </Box>
        ) : (
          <Chip
            variant={pttActive ? 'Success' : 'Warning'}
            fill="Soft"
            radii="400"
            style={{
              position: 'absolute',
              top: '-2.2rem',
              left: '50%',
              transform: 'translateX(-50%)',
              pointerEvents: 'none',
              whiteSpace: 'nowrap',
            }}
            outlined
          >
            <Text size="T200" style={{ fontWeight: 700 }}>
              {pttActive ? '● Live' : `PTT — Hold ${pttKeyLabel}`}
            </Text>
          </Chip>
        )
      )}
      {shareConfirm && (
        <Box
          style={{
            position: 'absolute',
            bottom: '110%',
            left: '50%',
            transform: 'translateX(-50%)',
            background: 'var(--bg-surface)',
            border: '1px solid var(--border-color)',
            borderRadius: '0.75rem',
            padding: '1rem 1.25rem',
            zIndex: 100,
            minWidth: '260px',
            boxShadow: '0 8px 32px rgba(0,0,0,0.35)',
            display: 'flex',
            flexDirection: 'column',
            gap: '0.75rem',
          }}
        >
          <Text size="T300" style={{ fontWeight: 600 }}>Share your screen?</Text>
          <Text size="T200" style={{ opacity: 0.75 }}>Your screen will be visible to all participants in this call.</Text>
          <Box gap="200">
            <Button
              size="300" variant="Success" fill="Solid" radii="300"
              onClick={() => { callEmbed.control.toggleScreenshare(); setShareConfirm(false); }}
            >
              <Text size="B300">Share</Text>
            </Button>
            <Button
              size="300" variant="Surface" fill="Soft" radii="300" outlined
              onClick={() => setShareConfirm(false)}
            >
              <Text size="B300">Cancel</Text>
            </Button>
          </Box>
        </Box>
      )}
      <SequenceCard
        className={css.ControlCard}
        variant="SurfaceVariant"
        gap="400"
        radii="500"
        alignItems="Center"
        justifyContent="SpaceBetween"
      >
        <Box alignItems="Center" gap="Inherit" grow="Yes" direction={compact ? 'Column' : 'Row'}>
          <Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200">
            <MicrophoneButton
              enabled={microphone}
              onToggle={() => callEmbed.control.toggleMicrophone()}
            />
            <SoundButton enabled={sound} onToggle={() => callEmbed.control.toggleSound()} />
          </Box>
          {!compact && <ControlDivider />}
          <Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200">
            <VideoButton enabled={video} onToggle={() => callEmbed.control.toggleVideo()} />
            <ScreenShareButton
              enabled={screenshare}
              onToggle={() => screenshare
                ? callEmbed.control.toggleScreenshare()
                : setShareConfirm(true)
              }
            />
          </Box>
        </Box>
        {!compact && <ControlDivider />}
        <Box alignItems="Center" gap="Inherit" grow="Yes" direction={compact ? 'Column' : 'Row'}>
          <Box shrink="No" alignItems="Inherit" justifyContent="Inherit" gap="200">
            <ChatButton />
            <PopOut
              anchor={cords}
              position="Top"
              align="Center"
              content={
                <FocusTrap
                  focusTrapOptions={{
                    initialFocus: false,
                    onDeactivate: () => setCords(undefined),
                    clickOutsideDeactivates: true,
                    isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
                    isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
                    escapeDeactivates: stopPropagation,
                  }}
                >
                  <Menu>
                    <Box direction="Column" style={{ padding: config.space.S100 }}>
                      <MenuItem
                        size="300"
                        variant="Surface"
                        radii="300"
                        onClick={handleSpotlightClick}
                      >
                        <Text size="B300" truncate>
                          {spotlight ? 'Grid View' : 'Spotlight View'}
                        </Text>
                      </MenuItem>
                      <MenuItem
                        size="300"
                        variant="Surface"
                        radii="300"
                        onClick={handleReactionsClick}
                      >
                        <Text size="B300" truncate>
                          Reactions
                        </Text>
                      </MenuItem>
                      <MenuItem
                        size="300"
                        variant="Surface"
                        radii="300"
                        onClick={handleSettingsClick}
                      >
                        <Text size="B300" truncate>
                          Settings
                        </Text>
                      </MenuItem>
                    </Box>
                  </Menu>
                </FocusTrap>
              }
            >
              <IconButton
                variant="Surface"
                fill="Soft"
                radii="400"
                size="400"
                onClick={handleOpenMenu}
                outlined
                aria-pressed={!!cords}
              >
                <Icon size="400" src={Icons.VerticalDots} />
              </IconButton>
            </PopOut>
          </Box>
          <Box shrink="No" direction="Column">
            <Button
              style={{ minWidth: toRem(88) }}
              variant="Critical"
              fill="Solid"
              onClick={hangup}
              before={
                exiting ? (
                  <Spinner variant="Critical" fill="Solid" size="200" />
                ) : (
                  <Icon src={Icons.PhoneDown} size="200" filled />
                )
              }
              disabled={exiting}
            >
              <Text size="B400">End</Text>
            </Button>
          </Box>
        </Box>
      </SequenceCard>
    </Box>
  );
}
