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

import { useAuth } from '../context/AuthContext';
import { type CallMode, useCall } from '../context/CallContext';
import {
  getPttSettings,
  type PttSettings,
  subscribePttSettings,
} from '../lib/pttSettings';
import { useActiveSpeakers } from '../lib/useActiveSpeakers';
import { CallControls } from './CallControls';
import { CallParticipantTile } from './CallParticipantTile';
import { FocusIcon, GridIcon, LockIcon, MaximizeIcon, SpinnerIcon, UsersIcon } from './icons';
import { ScreenShareViewer } from './ScreenShareViewer';

// Discord-style in-call dock rendered above the message list. Renders three
// visual modes driven by CallContext.callMode: grid, focus, fullscreen.
// The fullscreen variant absolute-positions itself over the conversation
// container so the rail+chat-list remain visible on the left.
interface Props {
  conversation: ConversationSummary;
}

interface Tile {
  userId: string;
  displayName: string;
  avatarUrl: string | null;
  self: boolean;
  muted: boolean;
  video: boolean;
  sharing: boolean;
  remoteSharing: boolean;
}

export function InCallPanel({ conversation }: Props) {
  const { t } = useTranslation(['app']);
  const {
    state,
    room,
    remoteParticipants,
    isMuted,
    isE2EEActive,
    isScreenSharing,
    remoteScreenShares,
    callMode,
    focusedId,
    toggleMute,
    toggleScreenShare,
    hangup,
    setCallMode,
    setFocusedId,
  } = useCall();
  const { session } = useAuth();
  const myId = session?.user.id ?? null;
  const activeSpeakers = useActiveSpeakers(room);

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

  const tiles = buildTiles({
    conversation,
    myId,
    remoteIdentities: remoteParticipants.map((p) => p.identity),
    isMuted,
    isScreenSharing,
    remoteSharerIds: new Set(remoteScreenShares.map((s) => s.participantId)),
  });

  const duration =
    state.kind === 'connected'
      ? <LiveDuration startedAt={state.startedAt} />
      : null;

  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');

  const sharingTile = tiles.find((p) => p.sharing);
  const effectiveFocusedId = focusedId ?? sharingTile?.userId ?? tiles[0]?.userId ?? null;
  const speaker = tiles.find((p) => p.userId === effectiveFocusedId) ?? tiles[0];

  const controls = (
    <CallControls
      muted={isMuted}
      sharing={isScreenSharing}
      video={false}
      onToggleMute={toggleMute}
      onToggleShare={() => void toggleScreenShare()}
      onHangup={() => void hangup()}
      compact={callMode !== 'fullscreen'}
      glass={callMode === 'fullscreen'}
      disabledMedia={state.kind !== 'connected'}
    />
  );

  if (callMode === 'fullscreen') {
    return (
      <FullscreenCall
        tiles={tiles}
        speaker={speaker}
        remoteScreenShares={remoteScreenShares}
        conversationMembers={conversation.members}
        activeSpeakers={activeSpeakers}
        e2ee={isE2EEActive}
        onExit={() => setCallMode('grid')}
        onFocusTile={(id) => {
          setFocusedId(id);
        }}
        controls={controls}
      />
    );
  }

  const title =
    conversation.type === 'group'
      ? conversation.name ?? t('app:chats.new_group')
      : conversation.peer?.displayName ?? '—';

  return (
    <section
      aria-label={t('app:call.in_call', { defaultValue: 'Im Anruf' })}
      className="flex min-h-[280px] max-h-[420px] shrink-0 flex-col overflow-hidden border-b border-line bg-surface-2"
      style={{ height: '50%' }}
    >
      <div className="flex items-center justify-between border-b border-line bg-surface-3 px-4 py-2">
        <div className="flex min-w-0 flex-col gap-0.5">
          <div className="flex items-center gap-2 text-sm font-semibold text-fg">
            <UsersIcon className="h-4 w-4 shrink-0 text-fg-muted" />
            <span className="truncate">{title}</span>
            <span className="text-fg-muted/50" aria-hidden="true">·</span>
            <span className="tabular-nums text-fg-muted">
              {duration ?? statusLabel}
              {state.kind !== 'connected' && (
                <SpinnerIcon className="ml-1 inline h-3 w-3" />
              )}
            </span>
          </div>
          {isE2EEActive && (
            <div className="flex items-center gap-1 text-[11px] font-medium text-emerald-600 dark:text-emerald-400">
              <LockIcon className="h-3 w-3" />
              <span>{t('app:call.e2ee_active', { defaultValue: 'E2E verschlüsselt' })}</span>
            </div>
          )}
        </div>
        <ModeToggles mode={callMode} onChange={setCallMode} />
      </div>

      <CallStage
        tiles={tiles}
        speaker={speaker}
        mode={callMode}
        activeSpeakers={activeSpeakers}
        e2ee={isE2EEActive}
        remoteScreenShares={remoteScreenShares}
        conversationMembers={conversation.members}
        onFocusTile={(id) => {
          setFocusedId(id);
          if (callMode === 'grid') setCallMode('focus');
        }}
        compact
      />

      {controls}

      <PttHint />
    </section>
  );
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

interface BuildArgs {
  conversation: ConversationSummary;
  myId: string | null;
  remoteIdentities: string[];
  isMuted: boolean;
  isScreenSharing: boolean;
  remoteSharerIds: Set<string>;
}

function buildTiles({
  conversation,
  myId,
  remoteIdentities,
  isMuted,
  isScreenSharing,
  remoteSharerIds,
}: BuildArgs): Tile[] {
  const remoteSet = new Set(remoteIdentities);
  const out: Tile[] = [];
  if (myId) {
    const me = conversation.members.find((m) => m.userId === myId) ?? null;
    out.push({
      userId: myId,
      displayName: me?.profile?.displayName ?? '?',
      avatarUrl: me?.profile?.avatarUrl ?? null,
      self: true,
      muted: isMuted,
      video: false,
      sharing: isScreenSharing,
      remoteSharing: false,
    });
  }
  for (const m of conversation.members) {
    if (m.userId === myId) continue;
    if (!remoteSet.has(m.userId)) continue;
    const sharing = remoteSharerIds.has(m.userId);
    out.push({
      userId: m.userId,
      displayName: m.profile?.displayName ?? '?',
      avatarUrl: m.profile?.avatarUrl ?? null,
      self: false,
      muted: false,
      video: false,
      sharing,
      remoteSharing: sharing,
    });
  }
  return out;
}

function LiveDuration({ startedAt }: { startedAt: string }) {
  const [, tick] = useState(0);
  useEffect(() => {
    const id = window.setInterval(() => tick((v) => v + 1), 1000);
    return () => window.clearInterval(id);
  }, []);
  return <>{formatElapsed(Date.now() - new Date(startedAt).getTime())}</>;
}

function formatElapsed(ms: number): string {
  const total = Math.max(0, Math.floor(ms / 1000));
  const hh = Math.floor(total / 3600);
  const mm = Math.floor((total % 3600) / 60);
  const ss = total % 60;
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${pad(hh)}:${pad(mm)}:${pad(ss)}`;
}

function ModeToggles({
  mode,
  onChange,
}: {
  mode: CallMode;
  onChange: (mode: CallMode) => void;
}) {
  return (
    <div className="flex items-center gap-1">
      <ModeButton active={mode === 'grid'} onClick={() => onChange('grid')} label="Grid">
        <GridIcon className="h-4 w-4" />
      </ModeButton>
      <ModeButton active={mode === 'focus'} onClick={() => onChange('focus')} label="Fokus">
        <FocusIcon className="h-4 w-4" />
      </ModeButton>
      <ModeButton
        active={mode === 'fullscreen'}
        onClick={() => onChange('fullscreen')}
        label="Vollbild"
      >
        <MaximizeIcon className="h-4 w-4" />
      </ModeButton>
    </div>
  );
}

function ModeButton({
  active,
  onClick,
  label,
  children,
}: {
  active: boolean;
  onClick: () => void;
  label: string;
  children: React.ReactNode;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={label}
      aria-pressed={active}
      title={label}
      className={
        'flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border transition focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 ' +
        (active
          ? 'border-accent bg-accent text-accent-fg'
          : 'border-line bg-surface-2 text-fg-muted hover:bg-surface-3 hover:text-fg')
      }
    >
      {children}
    </button>
  );
}

interface StageProps {
  tiles: Tile[];
  speaker: Tile | undefined;
  mode: CallMode;
  activeSpeakers: Set<string>;
  e2ee: boolean;
  remoteScreenShares: {
    track: import('livekit-client').RemoteTrack;
    participantId: string;
    participantName: string;
  }[];
  conversationMembers: ConversationSummary['members'];
  onFocusTile: (id: string) => void;
  compact?: boolean;
}

function CallStage({
  tiles,
  speaker,
  mode,
  activeSpeakers,
  e2ee,
  remoteScreenShares,
  conversationMembers,
  onFocusTile,
  compact = false,
}: StageProps) {
  if (mode === 'focus' && speaker) {
    const others = tiles.filter((p) => p.userId !== speaker.userId);
    return (
      <div className="flex min-h-0 flex-1 flex-col gap-2.5 p-3">
        <div className="min-h-0 flex-1">
          <FocusedTile
            tile={speaker}
            e2ee={e2ee}
            speaking={activeSpeakers.has(speaker.userId)}
            remoteScreenShares={remoteScreenShares}
            conversationMembers={conversationMembers}
          />
        </div>
        {others.length > 0 && (
          <div className="flex h-[110px] gap-2.5 overflow-x-auto">
            {others.map((p) => (
              <div key={p.userId} className="h-full min-w-[160px]">
                <CallParticipantTile
                  userId={p.userId}
                  displayName={p.displayName}
                  avatarUrl={p.avatarUrl}
                  me={p.self}
                  muted={p.muted}
                  speaking={activeSpeakers.has(p.userId)}
                  sharing={p.sharing}
                  video={p.video}
                  e2ee={e2ee}
                  size="small"
                  onClick={() => onFocusTile(p.userId)}
                />
              </div>
            ))}
          </div>
        )}
      </div>
    );
  }

  // Grid
  const gridClass = gridColsFor(tiles.length);
  return (
    <div className={'min-h-0 flex-1 p-3 ' + (compact ? '' : 'p-4')}>
      <div className={'grid h-full gap-2 ' + gridClass}>
        {tiles.map((p) => (
          <CallParticipantTile
            key={p.userId}
            userId={p.userId}
            displayName={p.displayName}
            avatarUrl={p.avatarUrl}
            me={p.self}
            muted={p.muted}
            speaking={activeSpeakers.has(p.userId)}
            sharing={p.sharing}
            video={p.video}
            e2ee={e2ee}
            onClick={() => onFocusTile(p.userId)}
          />
        ))}
      </div>
    </div>
  );
}

function FocusedTile({
  tile,
  e2ee,
  speaking,
  remoteScreenShares,
  conversationMembers,
}: {
  tile: Tile;
  e2ee: boolean;
  speaking: boolean;
  remoteScreenShares: StageProps['remoteScreenShares'];
  conversationMembers: StageProps['conversationMembers'];
}) {
  // When the focused participant is remotely sharing their screen, embed the
  // real video stream rather than the fake-window placeholder.
  if (tile.remoteSharing) {
    const share = remoteScreenShares.find((s) => s.participantId === tile.userId);
    const member = conversationMembers.find((m) => m.userId === tile.userId);
    if (share) {
      return (
        <div className="h-full">
          <ScreenShareViewer
            share={share}
            avatarUrl={member?.profile?.avatarUrl ?? tile.avatarUrl}
            displayName={member?.profile?.displayName ?? tile.displayName}
          />
        </div>
      );
    }
  }
  return (
    <div className="h-full">
      <CallParticipantTile
        userId={tile.userId}
        displayName={tile.displayName}
        avatarUrl={tile.avatarUrl}
        me={tile.self}
        muted={tile.muted}
        speaking={speaking}
        sharing={tile.sharing}
        video={tile.video}
        e2ee={e2ee}
        focused
      />
    </div>
  );
}

function gridColsFor(n: number): string {
  if (n <= 1) return 'grid-cols-1';
  if (n === 2) return 'grid-cols-2';
  if (n === 3) return 'grid-cols-3';
  if (n === 4) return 'grid-cols-2 grid-rows-2';
  return 'grid-cols-3 grid-rows-2';
}

// ---------------------------------------------------------------------------
// Fullscreen cinema mode
// ---------------------------------------------------------------------------

interface FullscreenProps {
  tiles: Tile[];
  speaker: Tile | undefined;
  remoteScreenShares: StageProps['remoteScreenShares'];
  conversationMembers: StageProps['conversationMembers'];
  activeSpeakers: Set<string>;
  e2ee: boolean;
  onExit: () => void;
  onFocusTile: (id: string) => void;
  controls: React.ReactNode;
}

function FullscreenCall({
  tiles,
  speaker,
  remoteScreenShares,
  conversationMembers,
  activeSpeakers,
  e2ee,
  onExit: _onExit,
  onFocusTile,
  controls,
}: FullscreenProps) {
  const others = speaker ? tiles.filter((p) => p.userId !== speaker.userId) : tiles;
  const [hintGone, setHintGone] = useState(false);
  useEffect(() => {
    const id = window.setTimeout(() => setHintGone(true), 3500);
    return () => window.clearTimeout(id);
  }, []);

  return (
    <div className="fixed inset-0 z-[60] flex flex-col overflow-hidden bg-surface">
      <div className="relative min-h-0 flex-1">
        {speaker && (
          <div className="absolute inset-0">
            {speaker.remoteSharing ? (
              <FullscreenShare speaker={speaker} remoteScreenShares={remoteScreenShares} conversationMembers={conversationMembers} />
            ) : (
              <div className="h-full w-full [&>div]:rounded-none [&>div]:border-0">
                <CallParticipantTile
                  userId={speaker.userId}
                  displayName={speaker.displayName}
                  avatarUrl={speaker.avatarUrl}
                  me={speaker.self}
                  muted={speaker.muted}
                  speaking={activeSpeakers.has(speaker.userId)}
                  sharing={speaker.sharing}
                  video={speaker.video}
                  e2ee={e2ee}
                  focused
                />
              </div>
            )}
          </div>
        )}

        {others.length > 0 && (
          <div className="absolute bottom-24 right-4 flex w-[180px] flex-col gap-2">
            {others.slice(0, 4).map((p) => (
              <div key={p.userId} className="h-[100px] backdrop-blur-xl">
                <CallParticipantTile
                  userId={p.userId}
                  displayName={p.displayName}
                  avatarUrl={p.avatarUrl}
                  me={p.self}
                  muted={p.muted}
                  speaking={activeSpeakers.has(p.userId)}
                  sharing={p.sharing}
                  video={p.video}
                  e2ee={e2ee}
                  size="small"
                  onClick={() => onFocusTile(p.userId)}
                />
              </div>
            ))}
          </div>
        )}

        {!hintGone && (
          <div
            aria-hidden="true"
            className="pointer-events-none absolute left-1/2 top-5 z-10 animate-fs-hint rounded-lg border border-white/10 bg-black/60 px-3.5 py-1.5 text-[11px] font-medium tracking-wide text-white/70 backdrop-blur-md"
          >
            Esc zum Verlassen
          </div>
        )}

        <div className="pointer-events-auto absolute bottom-4 left-1/2 -translate-x-1/2">
          {controls}
        </div>
      </div>
    </div>
  );
}

function FullscreenShare({
  speaker,
  remoteScreenShares,
  conversationMembers,
}: {
  speaker: Tile;
  remoteScreenShares: StageProps['remoteScreenShares'];
  conversationMembers: StageProps['conversationMembers'];
}) {
  const share = remoteScreenShares.find((s) => s.participantId === speaker.userId);
  const member = conversationMembers.find((m) => m.userId === speaker.userId);
  if (!share) return null;
  return (
    <div className="h-full w-full">
      <ScreenShareViewer
        share={share}
        avatarUrl={member?.profile?.avatarUrl ?? speaker.avatarUrl}
        displayName={member?.profile?.displayName ?? speaker.displayName}
      />
    </div>
  );
}

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