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

import { useAuth } from '../context/AuthContext';
import { useCall } from '../context/CallContext';
import { useCallPresence } from '../lib/useCallPresence';
import type { PeerPresence } from '../lib/usePeerPresence';
import { Avatar } from './Avatar';
import {
  InfoIcon,
  PhoneIcon,
  SearchIcon,
  SpinnerIcon,
  UsersIcon,
  VideoIcon,
} from './icons';

const PRESENCE_DOT: Record<PresenceState, string> = {
  online: 'bg-emerald-500',
  idle: 'bg-amber-400',
  dnd: 'bg-rose-500',
  invisible: 'bg-neutral-500',
  offline: 'bg-neutral-400 dark:bg-neutral-600',
};

interface Props {
  conversation: ConversationSummary | null;
  peerPresence: PeerPresence | null;
  onInfoClick?: () => void;
  onSearchClick?: () => void;
}

export function ConversationHeader({ conversation, peerPresence, onInfoClick, onSearchClick }: Props) {
  if (!conversation) {
    return <header className="h-[57px] border-b border-line px-6 py-3" aria-busy="true" />;
  }

  return (
    <>
      <HeaderBar
        conversation={conversation}
        peerPresence={peerPresence}
        {...(onInfoClick ? { onInfoClick } : {})}
        {...(onSearchClick ? { onSearchClick } : {})}
      />
      <ActiveCallBanner conversationId={conversation.id} />
    </>
  );
}

interface HeaderBarProps {
  conversation: ConversationSummary;
  peerPresence: PeerPresence | null;
  onInfoClick?: () => void;
  onSearchClick?: () => void;
}

function HeaderBar({ conversation, peerPresence, onInfoClick, onSearchClick }: HeaderBarProps) {
  const { t } = useTranslation(['app']);

  const isDm = conversation.type === 'dm';
  const title = isDm ? (conversation.peer?.displayName ?? '?') : (conversation.name ?? '?');
  const handle = isDm ? '@' + (conversation.peer?.username ?? '?') : '';
  const peerAvatar = isDm ? (conversation.peer?.avatarUrl ?? null) : (conversation.avatarUrl ?? null);

  // Hide presence when peer chose invisible — reciprocal privacy.
  const peerState = peerPresence?.state ?? null;
  const showPresence = isDm && peerState && peerState !== 'invisible';
  // Subtitle priority: custom status_message when online (or idle/dnd), else
  // the localized presence label. Offline always wins → just "Offline".
  const presenceLabel = (() => {
    if (!peerState) return '';
    if (peerState === 'offline') return t('app:presence.offline');
    if (peerPresence?.statusMessage && peerPresence.statusMessage.trim().length > 0) {
      return peerPresence.statusMessage.trim();
    }
    return t('app:presence.' + peerState);
  })();

  return (
    <header className="flex items-center gap-3 border-b border-line bg-surface-3 px-6 py-3">
      <div className="relative">
        {isDm ? (
          <Avatar url={peerAvatar} displayName={title} className="h-10 w-10 text-base" />
        ) : peerAvatar ? (
          <Avatar url={peerAvatar} displayName={title} className="h-10 w-10 text-base" />
        ) : (
          <div className="flex h-10 w-10 items-center justify-center rounded-full bg-accent/20 text-accent">
            <UsersIcon className="h-5 w-5" />
          </div>
        )}
        {showPresence && peerState && (
          <span
            aria-hidden="true"
            className={
              'absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full ring-2 ring-surface-3 ' +
              PRESENCE_DOT[peerState]
            }
          />
        )}
      </div>
      <div className="min-w-0 flex-1">
        <p className="truncate font-display text-base font-semibold text-fg">{title}</p>
        <p className="truncate text-xs text-fg-muted">
          {isDm ? (
            <>
              <span>{handle}</span>
              {showPresence && (
                <>
                  <span className="mx-1.5 text-fg-muted/50">·</span>
                  <span>{presenceLabel}</span>
                </>
              )}
            </>
          ) : (
            <>
              {conversation.members.length} {t('app:nav.friends').toLowerCase()}
            </>
          )}
        </p>
      </div>

      <HeaderActionButton
        label={t('app:chats.search', { defaultValue: 'Suche' })}
        icon={SearchIcon}
        {...(onSearchClick ? { onClick: onSearchClick } : {})}
      />
      <CallHeaderButton conversationId={conversation.id} kind="audio" />
      <CallHeaderButton conversationId={conversation.id} kind="video" />
      {!isDm && onInfoClick && (
        <HeaderActionButton
          label={t('app:group.info_title')}
          icon={InfoIcon}
          onClick={onInfoClick}
        />
      )}
    </header>
  );
}

interface HeaderActionButtonProps {
  label: string;
  icon: (props: React.SVGProps<SVGSVGElement>) => React.JSX.Element;
  onClick?: () => void;
  disabled?: boolean;
  tone?: 'default' | 'accent';
}

function HeaderActionButton({
  label,
  icon: Icon,
  onClick,
  disabled,
  tone = 'default',
}: HeaderActionButtonProps) {
  const toneClass =
    tone === 'accent'
      ? 'text-accent hover:bg-accent/10'
      : 'text-fg-muted hover:bg-surface-2 hover:text-fg';
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      aria-label={label}
      title={label}
      className={
        'flex h-9 w-9 cursor-pointer items-center justify-center rounded-lg transition focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40 disabled:cursor-not-allowed disabled:opacity-50 ' +
        toneClass
      }
    >
      <Icon className="h-4 w-4" />
    </button>
  );
}

function CallHeaderButton({
  conversationId,
  kind,
}: {
  conversationId: string;
  kind: 'audio' | 'video';
}) {
  const { t } = useTranslation(['app']);
  const { state, startCall } = useCall();
  const busy = state.kind !== 'idle';
  const label =
    kind === 'video'
      ? t('app:call.start_video', { defaultValue: 'Video-Anruf' })
      : t('app:call.start_audio');
  const Icon = kind === 'video' ? VideoIcon : PhoneIcon;
  return (
    <HeaderActionButton
      label={busy ? t('app:call.busy') : label}
      icon={Icon}
      onClick={() => void startCall(conversationId, kind)}
      disabled={busy}
    />
  );
}

function ActiveCallBanner({ conversationId }: { conversationId: string }) {
  const { t } = useTranslation(['app']);
  const { session } = useAuth();
  const { state, joinActiveCall, lastCallConversationId, dismissLastCall } = useCall();
  const active = useCallPresence(conversationId);

  const myId = session?.user.id;
  const iAmIn =
    (state.kind === 'connected' ||
      state.kind === 'connecting' ||
      state.kind === 'outgoing') &&
    state.conversationId === conversationId;

  const othersIn = active.filter((u) => u !== myId);
  // Fallback signal: I just left this conv with peers still inside. Covers the
  // brief window after hangup where presence may not have re-synced yet (the
  // realtime channel can churn while ConversationHeader remounts).
  const justLeft = state.kind === 'idle' && lastCallConversationId === conversationId;

  // Once presence confirms the room is empty, drop the "just left" hint so the
  // banner hides cleanly instead of sticking forever. Grace window handles the
  // brief gap between hangup and presence re-sync so we don't flicker.
  useEffect(() => {
    if (!justLeft) return;
    if (othersIn.length > 0) return; // still live — keep banner
    const id = window.setTimeout(() => dismissLastCall(), 3000);
    return () => window.clearTimeout(id);
  }, [justLeft, othersIn.length, dismissLastCall]);

  if (iAmIn) return null;
  if (othersIn.length === 0 && !justLeft) return null;

  const count = Math.max(othersIn.length, justLeft ? 1 : 0);
  const busy = state.kind !== 'idle';
  return (
    <div className="flex items-center gap-3 border-b border-emerald-500/30 bg-emerald-500/10 px-6 py-2.5 text-sm text-emerald-700 dark:text-emerald-100">
      <PhoneIcon className="h-4 w-4 text-emerald-600 dark:text-emerald-300" />
      <span className="flex-1">
        {t('app:call.active_in_conv', {
          defaultValue: 'Active call · {{count}} in room',
          count,
        })}
      </span>
      <button
        type="button"
        onClick={() => void joinActiveCall(conversationId, 'audio')}
        disabled={busy}
        className="inline-flex cursor-pointer items-center gap-1.5 rounded-md bg-emerald-600 px-3 py-1.5 text-xs font-semibold text-white transition hover:bg-emerald-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400/40 disabled:cursor-not-allowed disabled:opacity-60"
      >
        {busy ? (
          <SpinnerIcon className="h-3.5 w-3.5" />
        ) : (
          <PhoneIcon className="h-3.5 w-3.5" />
        )}
        <span>{t('app:call.join', { defaultValue: 'Join' })}</span>
      </button>
    </div>
  );
}
