import type { ConversationSummary } from '@chat-app/shared/chat';
import type { RemoteTrack } from 'livekit-client';
import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { useAuth } from '../context/AuthContext';
import { type RemoteScreenShare, useCall } from '../context/CallContext';
import {
  getPttSettings,
  type PttSettings,
  subscribePttSettings,
} from '../lib/pttSettings';
import {
  LockIcon,
  MicIcon,
  MicOffIcon,
  MonitorShareIcon,
  MonitorStopIcon,
  PhoneOffIcon,
  SpinnerIcon,
} from './icons';

interface Props {
  conversation: ConversationSummary;
}

// Discord-style call widget rendered above the message list when the user is
// in the current conversation's call. Shows participant avatars + controls.
export function InCallPanel({ conversation }: Props) {
  const { t } = useTranslation(['app']);
  const {
    state,
    remoteParticipants,
    isMuted,
    isE2EEActive,
    toggleMute,
    hangup,
    isScreenSharing,
    remoteScreenShares,
    toggleScreenShare,
  } = useCall();
  const { session } = useAuth();
  const myId = session?.user.id ?? null;

  const active =
    (state.kind === 'connected' ||
      state.kind === 'connecting' ||
      state.kind === 'outgoing') &&
    state.conversationId === conversation.id;
  if (!active) return null;

  const remoteIds = new Set<string>(
    remoteParticipants.map((p) => p.identity).filter((s): s is string => Boolean(s)),
  );
  const tiles: ParticipantTileData[] = [];
  if (myId) {
    const me = conversation.members.find((m) => m.userId === myId) ?? null;
    tiles.push({
      userId: myId,
      displayName: me?.profile?.displayName ?? '?',
      avatarUrl: me?.profile?.avatarUrl ?? null,
      self: true,
      speaking: false,
      muted: isMuted,
    });
  }
  for (const m of conversation.members) {
    if (m.userId === myId) continue;
    if (!remoteIds.has(m.userId)) continue;
    tiles.push({
      userId: m.userId,
      displayName: m.profile?.displayName ?? '?',
      avatarUrl: m.profile?.avatarUrl ?? null,
      self: false,
      speaking: false,
      muted: false,
    });
  }

  const statusLabel =
    state.kind === 'outgoing'
      ? t('app:call.outgoing_ringing')
      : state.kind === 'connecting'
        ? t('app:call.connecting')
        : remoteParticipants.length === 0
          ? t('app:call.waiting_for_peers', { defaultValue: 'Warte auf andere…' })
          : t('app:call.connected');

  return (
    <section
      aria-label={t('app:call.in_call', { defaultValue: 'Im Anruf' })}
      className="border-b border-white/5 bg-gradient-to-b from-ink-900/80 to-ink-950/40 px-6 py-5"
    >
      <div className="mb-4 flex items-center gap-2 text-xs font-medium text-emerald-300">
        {state.kind === 'connecting' ? (
          <SpinnerIcon className="h-3.5 w-3.5" />
        ) : (
          <span className="relative flex h-2 w-2">
            <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400/60" />
            <span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-400" />
          </span>
        )}
        <span className="uppercase tracking-wide">{statusLabel}</span>
        {isE2EEActive && (
          <span
            className="ml-2 inline-flex items-center gap-1 rounded-full bg-emerald-500/15 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-emerald-200 ring-1 ring-emerald-400/30"
            title={t('app:call.e2ee_active_hint', {
              defaultValue: 'Audio + Video sind Ende-zu-Ende-verschlüsselt',
            })}
          >
            <LockIcon className="h-3 w-3" />
            E2EE
          </span>
        )}
      </div>

      <div className="flex flex-wrap justify-center gap-4">
        {tiles.map((p) => (
          <ParticipantTile key={p.userId} {...p} />
        ))}
      </div>

      {remoteScreenShares.length > 0 && (
        <div className="mt-4 space-y-3">
          {remoteScreenShares.map((s) => {
            const member = conversation.members.find((m) => m.userId === s.participantId);
            return (
              <ScreenShareViewer
                key={s.track.sid ?? s.participantId}
                share={s}
                avatarUrl={member?.profile?.avatarUrl ?? null}
                displayName={member?.profile?.displayName ?? s.participantName}
              />
            );
          })}
        </div>
      )}

      <div className="mt-5 flex items-center justify-center gap-2">
        <ControlButton
          onClick={toggleMute}
          disabled={state.kind !== 'connected'}
          active={isMuted}
          label={isMuted ? t('app:call.unmute') : t('app:call.mute')}
          tone={isMuted ? 'amber' : 'neutral'}
        >
          {isMuted ? <MicOffIcon className="h-5 w-5" /> : <MicIcon className="h-5 w-5" />}
        </ControlButton>
        <ControlButton
          onClick={() => void toggleScreenShare()}
          disabled={state.kind !== 'connected'}
          active={isScreenSharing}
          label={
            isScreenSharing
              ? t('app:call.stop_share_screen', { defaultValue: 'Screen-Share stoppen' })
              : t('app:call.share_screen', { defaultValue: 'Bildschirm teilen' })
          }
          tone={isScreenSharing ? 'emerald' : 'neutral'}
        >
          {isScreenSharing ? (
            <MonitorStopIcon className="h-5 w-5" />
          ) : (
            <MonitorShareIcon className="h-5 w-5" />
          )}
        </ControlButton>
        <ControlButton
          onClick={() => void hangup()}
          label={t('app:call.hangup')}
          tone="rose"
        >
          <PhoneOffIcon className="h-5 w-5" />
        </ControlButton>
      </div>

      <PttHint />
    </section>
  );
}

interface ScreenShareViewerProps {
  share: RemoteScreenShare;
  avatarUrl: string | null;
  displayName: string;
}

function ScreenShareViewer({ share, avatarUrl, displayName }: ScreenShareViewerProps) {
  const { t } = useTranslation(['app']);
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [watching, setWatching] = useState(false);
  const [isFullscreen, setIsFullscreen] = useState(false);
  const letter = displayName.trim().charAt(0).toUpperCase() || '?';

  useEffect(() => {
    if (!watching) return;
    const el = videoRef.current;
    if (!el) return;
    const track: RemoteTrack = share.track;
    track.attach(el);
    return () => {
      track.detach(el);
    };
  }, [share.track, watching]);

  useEffect(() => {
    const onChange = () => {
      setIsFullscreen(document.fullscreenElement === containerRef.current);
    };
    document.addEventListener('fullscreenchange', onChange);
    return () => document.removeEventListener('fullscreenchange', onChange);
  }, []);

  const toggleFullscreen = () => {
    const el = containerRef.current;
    if (!el) return;
    if (document.fullscreenElement === el) {
      void document.exitFullscreen();
    } else {
      void el.requestFullscreen();
    }
  };

  return (
    <div
      ref={containerRef}
      className={
        'overflow-hidden rounded-xl border border-emerald-500/20 bg-black ' +
        (isFullscreen ? 'flex h-screen w-screen flex-col rounded-none' : '')
      }
    >
      <div className="flex shrink-0 items-center gap-2 border-b border-emerald-500/10 bg-emerald-500/10 px-3 py-1.5 text-xs text-emerald-200">
        <MonitorShareIcon className="h-3.5 w-3.5 shrink-0" />
        <span className="truncate flex-1">
          {t('app:call.is_sharing_screen', {
            name: displayName,
            defaultValue: displayName + ' teilt den Bildschirm',
          })}
        </span>
        {watching && (
          <>
            <button
              type="button"
              onClick={toggleFullscreen}
              aria-label={t('app:call.fullscreen', { defaultValue: 'Vollbild' })}
              title={t('app:call.fullscreen', { defaultValue: 'Vollbild' })}
              className="inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-emerald-200 transition hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400/40"
            >
              <FullscreenIcon className="h-3.5 w-3.5" />
            </button>
            <button
              type="button"
              onClick={() => {
                if (document.fullscreenElement === containerRef.current) {
                  void document.exitFullscreen();
                }
                setWatching(false);
              }}
              aria-label={t('app:call.stop_watching', { defaultValue: 'Nicht mehr anschauen' })}
              title={t('app:call.stop_watching', { defaultValue: 'Nicht mehr anschauen' })}
              className="inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-emerald-200 transition hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400/40"
            >
              <span aria-hidden="true" className="text-[14px] leading-none">×</span>
            </button>
          </>
        )}
      </div>

      {watching ? (
        <video
          ref={videoRef}
          autoPlay
          playsInline
          muted
          onDoubleClick={toggleFullscreen}
          className={
            'block cursor-zoom-in bg-black ' +
            (isFullscreen ? 'h-full w-full flex-1 object-contain' : 'w-full')
          }
        />
      ) : (
        <button
          type="button"
          onClick={() => setWatching(true)}
          aria-label={t('app:call.watch_screen', { defaultValue: 'Bildschirm anschauen' })}
          className="group relative block w-full cursor-pointer overflow-hidden bg-ink-900 focus:outline-none"
          style={{ aspectRatio: '16 / 9' }}
        >
          <BlurredTile avatarUrl={avatarUrl} letter={letter} />
          <div className="absolute inset-0 flex items-center justify-center bg-black/30 transition group-hover:bg-black/40">
            <div className="flex flex-col items-center gap-2">
              <span className="flex h-14 w-14 items-center justify-center rounded-full bg-emerald-500/90 text-white shadow-lg transition group-hover:scale-105">
                <PlayIcon className="ml-0.5 h-6 w-6" />
              </span>
              <span className="text-xs font-medium text-white/90">
                {t('app:call.watch_screen', { defaultValue: 'Bildschirm anschauen' })}
              </span>
            </div>
          </div>
        </button>
      )}
    </div>
  );
}

function BlurredTile({ avatarUrl, letter }: { avatarUrl: string | null; letter: string }) {
  if (avatarUrl) {
    return (
      <>
        <img
          src={avatarUrl}
          alt=""
          className="absolute inset-0 h-full w-full scale-110 object-cover blur-2xl"
        />
        <div className="absolute inset-0 bg-gradient-to-br from-brand-500/20 to-emerald-500/20" />
      </>
    );
  }
  return (
    <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-500/40 via-fuchsia-500/20 to-emerald-500/30">
      <span
        aria-hidden="true"
        className="text-[120px] font-display font-bold text-white/20 blur-[2px]"
      >
        {letter}
      </span>
    </div>
  );
}

function PlayIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" {...props}>
      <path d="M8 5v14l11-7z" />
    </svg>
  );
}

function FullscreenIcon(props: React.SVGProps<SVGSVGElement>) {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth={2}
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" />
    </svg>
  );
}

function PttHint() {
  const [ptt, setPtt] = useState<PttSettings>(() => getPttSettings());
  useEffect(() => subscribePttSettings(setPtt), []);
  if (!ptt.enabled) return null;
  return (
    <p className="mt-3 text-center text-[11px] text-neutral-500">
      Push-to-Talk:&nbsp;
      <kbd className="rounded border border-white/10 bg-white/5 px-1.5 py-0.5 font-mono text-[10px] text-neutral-300">
        {ptt.keyLabel}
      </kbd>
    </p>
  );
}

interface ParticipantTileData {
  userId: string;
  displayName: string;
  avatarUrl: string | null;
  self: boolean;
  speaking: boolean;
  muted: boolean;
}

function ParticipantTile(p: ParticipantTileData) {
  const letter = p.displayName.trim().charAt(0).toUpperCase() || '?';
  return (
    <div className="flex w-28 flex-col items-center gap-2">
      <div
        className={
          'relative flex h-20 w-20 items-center justify-center rounded-2xl bg-gradient-to-br from-brand-500/40 to-brand-700/40 text-2xl font-semibold text-white ring-2 transition ' +
          (p.speaking
            ? 'ring-emerald-400 shadow-[0_0_24px_rgba(52,211,153,0.35)]'
            : 'ring-white/10')
        }
      >
        {p.avatarUrl ? (
          <img
            src={p.avatarUrl}
            alt=""
            className="h-full w-full rounded-2xl object-cover"
          />
        ) : (
          <span aria-hidden="true">{letter}</span>
        )}
        {p.muted && (
          <span
            aria-hidden="true"
            className="absolute -bottom-1 -right-1 flex h-6 w-6 items-center justify-center rounded-full bg-amber-500 ring-2 ring-ink-950"
          >
            <MicOffIcon className="h-3 w-3 text-ink-950" />
          </span>
        )}
      </div>
      <p className="max-w-full truncate text-xs font-medium text-neutral-200">
        {p.displayName}
        {p.self && (
          <span className="ml-1 text-neutral-500">·&nbsp;Du</span>
        )}
      </p>
    </div>
  );
}

interface ControlButtonProps {
  onClick: () => void;
  label: string;
  tone: 'neutral' | 'amber' | 'rose' | 'emerald';
  active?: boolean;
  disabled?: boolean;
  children: React.ReactNode;
}

function ControlButton({ onClick, label, tone, disabled, children }: ControlButtonProps) {
  const toneClass =
    tone === 'rose'
      ? 'bg-rose-500 text-white hover:bg-rose-400 focus-visible:ring-rose-400/50'
      : tone === 'amber'
        ? 'bg-amber-500/90 text-ink-950 hover:bg-amber-400 focus-visible:ring-amber-400/50'
        : tone === 'emerald'
          ? 'bg-emerald-500/85 text-white hover:bg-emerald-400 focus-visible:ring-emerald-400/50'
          : 'bg-white/10 text-neutral-100 hover:bg-white/20 focus-visible:ring-brand-400/40';
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      aria-label={label}
      title={label}
      className={
        'inline-flex h-11 w-11 cursor-pointer items-center justify-center rounded-full transition focus:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 ' +
        toneClass
      }
    >
      {children}
    </button>
  );
}
