import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

import {
  getParticipantVolume,
  setParticipantVolume,
  subscribeParticipantVolumes,
} from '../lib/participantVolumes';
import {
  AtIcon,
  MicIcon,
  MicOffIcon,
  PinIcon,
  PinOffIcon,
} from './icons';

interface Props {
  userId: string;
  displayName: string;
  x: number;
  y: number;
  /** Discord-style pin toggle row at the top of the menu. When undefined,
   *  the row is hidden — used for tiles that don't make sense to pin. */
  pinned?: boolean;
  onTogglePin?: () => void;
  /** Hide the volume slider — for self-tiles where the slider would adjust
   *  the local user's own playback gain (which we don't expose). Defaults to
   *  true so existing call sites keep their behaviour. */
  renderVolume?: boolean;
  /** Discord-parity: open this user's profile card from the menu. When
   *  undefined the row is hidden (e.g. for self-tiles where it'd just open
   *  your own profile). */
  onShowProfile?: () => void;
  onClose: () => void;
}

const MENU_W = 240;
const MENU_H = 138;

export function ParticipantVolumeMenu({
  userId,
  displayName,
  x,
  y,
  pinned,
  onTogglePin,
  renderVolume = true,
  onShowProfile,
  onClose,
}: Props) {
  const [volume, setVolume] = useState<number>(() => getParticipantVolume(userId));
  // Remembers the volume before "Für mich stummschalten" so unmute restores
  // it instead of snapping back to 100%.
  const preMuteRef = useRef<number | null>(volume > 0 ? volume : null);

  // Re-sync from store in case another menu instance changed the same user.
  useEffect(() => subscribeParticipantVolumes(() => {
    setVolume(getParticipantVolume(userId));
  }), [userId]);

  // Outside click + Esc to close.
  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    const onDown = (e: MouseEvent) => {
      const target = e.target as HTMLElement | null;
      if (target?.closest('[data-volume-menu]')) return;
      onClose();
    };
    window.addEventListener('keydown', onKey);
    window.addEventListener('mousedown', onDown);
    return () => {
      window.removeEventListener('keydown', onKey);
      window.removeEventListener('mousedown', onDown);
    };
  }, [onClose]);

  const left = Math.min(Math.max(8, x), window.innerWidth - MENU_W - 8);
  const top = Math.min(Math.max(8, y), window.innerHeight - MENU_H - 8);

  return createPortal(
    <div
      data-volume-menu
      role="dialog"
      aria-label={'Lautstärke ' + displayName}
      style={{ left, top, width: MENU_W }}
      className="fixed z-[80] rounded-xl border border-line bg-surface-2/95 p-3 shadow-xl backdrop-blur-md"
    >
      <div className="mb-2 flex items-center justify-between gap-2 text-xs">
        <span className="truncate font-semibold text-fg">{displayName}</span>
        {renderVolume && (
          <span
            className={
              'tabular-nums ' + (volume > 1 ? 'text-amber-500' : 'text-fg-muted')
            }
          >
            {Math.round(volume * 100)}%
          </span>
        )}
      </div>
      {onShowProfile && (
        <button
          type="button"
          onClick={() => {
            onShowProfile();
            onClose();
          }}
          className="mb-1.5 flex w-full cursor-pointer items-center gap-2 rounded-md border border-line bg-surface-3 px-2.5 py-1.5 text-xs font-medium text-fg transition hover:border-accent hover:bg-accent/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40"
        >
          <AtIcon className="h-3.5 w-3.5" />
          <span>Profil anzeigen</span>
        </button>
      )}
      {renderVolume && (
        <button
          type="button"
          onClick={() => {
            // Discord-parity "Mute for me": toggle local playback gain.
            // Storing the pre-mute level lets unmute restore the user's
            // chosen volume (e.g. 130% → 0 → 130%) instead of snapping to 100.
            if (volume === 0) {
              const restored = preMuteRef.current ?? 1;
              setVolume(restored);
              setParticipantVolume(userId, restored);
            } else {
              preMuteRef.current = volume;
              setVolume(0);
              setParticipantVolume(userId, 0);
            }
          }}
          className={
            'mb-1.5 flex w-full cursor-pointer items-center gap-2 rounded-md border px-2.5 py-1.5 text-xs font-medium transition focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40 ' +
            (volume === 0
              ? 'border-rose-500/40 bg-rose-500/15 text-rose-600 hover:bg-rose-500/20 dark:text-rose-300'
              : 'border-line bg-surface-3 text-fg hover:border-accent hover:bg-accent/10')
          }
        >
          {volume === 0 ? (
            <MicIcon className="h-3.5 w-3.5" />
          ) : (
            <MicOffIcon className="h-3.5 w-3.5" />
          )}
          <span>{volume === 0 ? 'Lokalen Ton aktivieren' : 'Für mich stummschalten'}</span>
        </button>
      )}
      {onTogglePin && (
        <button
          type="button"
          onClick={() => {
            onTogglePin();
            onClose();
          }}
          className="mb-2 flex w-full cursor-pointer items-center gap-2 rounded-md border border-line bg-surface-3 px-2.5 py-1.5 text-xs font-medium text-fg transition hover:border-accent hover:bg-accent/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40"
        >
          {pinned ? <PinOffIcon className="h-3.5 w-3.5" /> : <PinIcon className="h-3.5 w-3.5" />}
          <span>{pinned ? 'Anpinnen aufheben' : 'Anpinnen'}</span>
        </button>
      )}
      {renderVolume && (
        <>
          {/* Up to 200% via WebAudio gain. Values above 100% can clip on loud
              mics — the amber count-up hints at that without a verbose warning. */}
          <input
            type="range"
            min={0}
            max={2}
            step={0.01}
            value={volume}
            onChange={(e) => {
              const v = Number(e.target.value);
              setVolume(v);
              setParticipantVolume(userId, v);
            }}
            aria-label={'Lautstärke ' + displayName}
            className="w-full accent-accent"
          />
          <div className="mt-1 flex justify-between text-[10px] text-fg-muted">
            <span>0%</span>
            <span className="tabular-nums">100%</span>
            <span>200%</span>
          </div>
        </>
      )}
    </div>,
    document.body,
  );
}
