import type { ProfileBrief } from '@chat-app/shared/friends';
import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';

import { getProfileAvatarPreviewUrl, getProfileCardStatusText } from '../lib/profileCard';
import { usePeerPresence } from '../lib/usePeerPresence';
import { Avatar } from './Avatar';
import { CopyIcon, MailIcon, SparklesIcon, XIcon } from './icons';

interface Props {
  userId: string;
  profile: ProfileBrief | null;
  x: number;
  y: number;
  onClose: () => void;
  onStartDm?: (userId: string) => void;
}

const PRESENCE_DOT: Record<string, 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',
};

const PRESENCE_LABEL: Record<string, string> = {
  online: 'Online',
  idle: 'Abwesend',
  dnd: 'Nicht stören',
  invisible: 'Offline',
  offline: 'Offline',
};

const CARD_W = 320;
// Banner is now aspect-[3/1] (≈107px tall at 320 wide) instead of the old
// fixed 80px → ~27px taller. Keep CARD_H in sync so the y-clamp doesn't run
// the card off the bottom of the viewport.
const CARD_H = 297;

// Hover/click card surfaced from avatars around the app. Shows display name,
// @handle, presence state + status message, plus a DM-start button when
// the clicked profile isn't the caller.
export function UserProfilePopover({ userId, profile, x, y, onClose, onStartDm }: Props) {
  // Subscribe to the same presence feed that the conversation header uses,
  // so status updates flow in live.
  const presence = usePeerPresence(userId);
  const [copied, setCopied] = useState(false);
  const [avatarPreviewOpen, setAvatarPreviewOpen] = useState(false);

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key !== 'Escape') return;
      if (avatarPreviewOpen) {
        setAvatarPreviewOpen(false);
        return;
      }
      onClose();
    };
    const onDown = (e: MouseEvent) => {
      const t = e.target as HTMLElement | null;
      if (t?.closest('[data-user-popover]')) return;
      if (t?.closest('[data-user-popover-trigger]')) return;
      onClose();
    };
    window.addEventListener('keydown', onKey);
    window.addEventListener('mousedown', onDown);
    return () => {
      window.removeEventListener('keydown', onKey);
      window.removeEventListener('mousedown', onDown);
    };
  }, [avatarPreviewOpen, onClose]);

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

  const displayName = profile?.displayName ?? '?';
  const username = profile?.username ?? '';
  const state = presence?.state ?? 'offline';
  const showPresence = state !== 'invisible';
  const statusMessage = presence?.statusMessage?.trim() ?? '';
  const profileStatusText = getProfileCardStatusText(statusMessage);
  const avatarPreviewUrl = getProfileAvatarPreviewUrl(profile?.avatarUrl);
  const presenceLabel = PRESENCE_LABEL[state] ?? PRESENCE_LABEL.offline;

  async function copyHandle() {
    const value = username ? '@' + username : userId;
    try {
      await navigator.clipboard.writeText(value);
      setCopied(true);
      window.setTimeout(() => setCopied(false), 1200);
    } catch (err: unknown) {
      console.warn('copy profile handle failed', err);
    }
  }

  return createPortal(
    <div
      data-user-popover
      role="dialog"
      aria-label={displayName}
      style={{ left, top, width: CARD_W }}
      className="fixed z-[80] overflow-hidden rounded-xl border border-line bg-surface-2/95 shadow-2xl backdrop-blur-md dark:bg-[#2b2d31]/95"
    >
      <div
        className={
          'aspect-[3/1] w-full bg-cover bg-center ' +
          (profile?.bannerUrl
            ? ''
            : 'bg-gradient-to-br from-accent/40 via-accent/15 to-surface-3')
        }
        style={
          profile?.bannerUrl
            ? { backgroundImage: 'url("' + profile.bannerUrl + '")' }
            : undefined
        }
      />
      <div className="px-4 pb-4">
        <div className="-mt-8 flex items-end justify-between gap-3">
          <button
            type="button"
            onClick={() => {
              if (avatarPreviewUrl) setAvatarPreviewOpen(true);
            }}
            disabled={!avatarPreviewUrl}
            className="relative rounded-full bg-surface-2 p-1 transition enabled:cursor-pointer enabled:hover:ring-2 enabled:hover:ring-accent/50 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 disabled:cursor-default dark:bg-[#2b2d31]"
            aria-label={avatarPreviewUrl ? 'Profilbild groß anzeigen' : displayName}
            title={avatarPreviewUrl ? 'Profilbild groß anzeigen' : displayName}
          >
            <Avatar
              url={profile?.avatarUrl ?? null}
              displayName={displayName}
              className="h-16 w-16 text-xl"
            />
            {showPresence && (
              <span
                aria-hidden="true"
                className={
                  'absolute bottom-1 right-1 h-4 w-4 rounded-full ring-2 ring-surface-2 dark:ring-[#2b2d31] ' +
                  (PRESENCE_DOT[state] ?? PRESENCE_DOT.offline)
                }
              />
            )}
          </button>
          <button
            type="button"
            onClick={() => void copyHandle()}
            className="mb-1 inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-lg text-fg-muted transition hover:bg-surface-3 hover:text-fg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40 dark:hover:bg-[#383a40]"
            aria-label="Handle kopieren"
            title="Handle kopieren"
          >
            <CopyIcon className="h-4 w-4" />
          </button>
        </div>

        <div className="mt-3 min-w-0">
          <p className="truncate font-display text-lg font-semibold text-fg">{displayName}</p>
          {username && <p className="truncate text-sm text-fg-muted">@{username}</p>}
        </div>

        <div className="mt-3 flex flex-wrap items-center gap-2">
          <span className="inline-flex items-center gap-1.5 rounded-full border border-line bg-surface-3 px-2.5 py-1 text-xs font-semibold text-fg dark:bg-[#383a40]">
            {showPresence && (
              <span
                aria-hidden="true"
                className={'h-2 w-2 rounded-full ' + (PRESENCE_DOT[state] ?? PRESENCE_DOT.offline)}
              />
            )}
            {presenceLabel}
          </span>
          {copied && (
            <span className="rounded-full bg-emerald-500/15 px-2.5 py-1 text-xs font-semibold text-emerald-600 dark:text-emerald-200">
              Kopiert
            </span>
          )}
        </div>

        <div className="mt-3 rounded-lg border border-line bg-surface-3 p-3 dark:bg-[#313338]">
          <p className="flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-fg-muted">
            <SparklesIcon className="h-3.5 w-3.5" />
            <span>Custom Status</span>
          </p>
          <p
            className={
              'mt-1.5 break-words text-sm ' +
              (statusMessage ? 'text-fg' : 'italic text-fg-muted')
            }
          >
            {profileStatusText}
          </p>
        </div>

        {onStartDm && (
          <button
            type="button"
            onClick={() => {
              onStartDm(userId);
              onClose();
            }}
            className="mt-3 inline-flex w-full cursor-pointer items-center justify-center gap-2 rounded-lg bg-accent px-3 py-2 text-sm font-semibold text-accent-fg transition hover:brightness-110 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50"
          >
            <MailIcon className="h-4 w-4" />
            <span>Nachricht senden</span>
          </button>
        )}
      </div>

      {avatarPreviewOpen && avatarPreviewUrl && (
        <AvatarPreviewDialog
          url={avatarPreviewUrl}
          displayName={displayName}
          onClose={() => setAvatarPreviewOpen(false)}
        />
      )}
    </div>,
    document.body,
  );
}

function AvatarPreviewDialog({
  url,
  displayName,
  onClose,
}: {
  url: string;
  displayName: string;
  onClose: () => void;
}) {
  useEffect(() => {
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      document.body.style.overflow = prevOverflow;
    };
  }, []);

  return createPortal(
    <div
      data-user-popover
      role="dialog"
      aria-modal="true"
      aria-label={'Profilbild von ' + displayName}
      onMouseDown={(e) => {
        if (e.currentTarget === e.target) onClose();
      }}
      className="fixed inset-0 z-[120] flex items-center justify-center bg-black/80 p-6 backdrop-blur-sm animate-fade-in"
    >
      <button
        type="button"
        onClick={onClose}
        aria-label="Schließen"
        title="Schließen"
        className="absolute right-4 top-4 flex h-10 w-10 cursor-pointer items-center justify-center rounded-full border border-white/10 bg-surface-3/90 text-fg transition hover:bg-surface-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 dark:bg-[#313338]/90 dark:hover:bg-[#383a40]"
      >
        <XIcon className="h-5 w-5" />
      </button>
      <img
        src={url}
        alt={'Profilbild von ' + displayName}
        draggable={false}
        onMouseDown={(e) => e.stopPropagation()}
        className="max-h-[82vh] max-w-[82vw] rounded-2xl object-contain shadow-2xl ring-1 ring-white/10"
      />
    </div>,
    document.body,
  );
}
