/**
 * MemberProfilePopout — Discord-style profile card that opens next
 * to the member list when the user clicks a member row. Anchored
 * against the clicked row's bounding rect and rendered via a portal
 * so it escapes sidebar clipping.
 */
import { useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { useQuery } from 'convex/react';
import { Key, PencilSimple, ShieldCheck } from '@phosphor-icons/react';
import { Avatar, Button } from '@discord-clone/ui';
import { api } from '../../../../../convex/_generated/api';
import type { Id } from '../../../../../convex/_generated/dataModel';
import { useOnlineUsers } from '../../contexts/PresenceContext';
import styles from './MemberProfilePopout.module.css';

export interface MemberProfilePopoutMember {
	userId: string;
	displayName: string;
	avatarUrl: string | null;
	status?: string;
}

interface MemberProfilePopoutProps {
	anchorRect: DOMRect;
	member: MemberProfilePopoutMember;
	onClose: () => void;
	onOpenProfile?: () => void;
	onOpenRoles?: () => void;
	/**
	 * Optional handler for "Rotate Encryption Key". When provided,
	 * renders a button that invokes it — currently only passed in by
	 * ChannelHeader when the open channel is a DM with this user.
	 * Returning a rejected promise leaves the busy state up to the
	 * caller; a resolved one closes the popout.
	 */
	onRotateKey?: () => Promise<void>;
}

const DEFAULT_ACCENT = '#4641D9';
const POPOUT_WIDTH = 320;
const POPOUT_GAP = 12;
const VIEWPORT_MARGIN = 16;

function mapPresence(
	status: string | undefined,
): 'online' | 'idle' | 'dnd' | 'offline' {
	switch (status) {
		case 'online':
			return 'online';
		case 'idle':
			return 'idle';
		case 'dnd':
			return 'dnd';
		default:
			return 'offline';
	}
}

export function MemberProfilePopout({
	anchorRect,
	member,
	onClose,
	onOpenProfile,
	onOpenRoles,
	onRotateKey,
}: MemberProfilePopoutProps) {
	const [rotating, setRotating] = useState(false);
	const [rotateStatus, setRotateStatus] = useState<
		{ type: 'success' | 'error'; message: string } | null
	>(null);
	const cardRef = useRef<HTMLDivElement>(null);
	const allUsers = useQuery(api.auth.getPublicKeys) ?? [];
	const localUserId =
		typeof localStorage !== 'undefined' ? localStorage.getItem('userId') : null;
	const myPerms = useQuery(
		api.roles.getMyPermissions,
		localUserId ? { userId: localUserId as Id<'userProfiles'> } : 'skip',
	);
	const canManageRoles = !!myPerms?.manage_roles;

	const fullUser = useMemo(
		() => allUsers.find((u) => u.id === member.userId),
		[allUsers, member.userId],
	);

	// Close on click-outside / Escape. mousedown intercepts before
	// any following click that might re-open the popout on another row.
	useEffect(() => {
		const handleClick = (e: MouseEvent) => {
			if (cardRef.current && !cardRef.current.contains(e.target as Node)) {
				onClose();
			}
		};
		const handleEscape = (e: KeyboardEvent) => {
			if (e.key === 'Escape') onClose();
		};
		document.addEventListener('mousedown', handleClick);
		document.addEventListener('keydown', handleEscape);
		return () => {
			document.removeEventListener('mousedown', handleClick);
			document.removeEventListener('keydown', handleEscape);
		};
	}, [onClose]);

	// Pull the target user's accentColor from their public profile
	// row so the popout reflects whatever they saved in Settings →
	// My Account. Falls back to the brand default when the user
	// hasn't picked one yet.
	const accent = (fullUser as any)?.accentColor || DEFAULT_ACCENT;

	// Position: anchor to the LEFT of the clicked row. The member
	// list sits on the right edge so the popout flows inward. Clamp
	// to the viewport so it never clips.
	const positionStyle = useMemo<React.CSSProperties>(() => {
		const rawLeft = anchorRect.left - POPOUT_WIDTH - POPOUT_GAP;
		const left = Math.max(
			VIEWPORT_MARGIN,
			Math.min(rawLeft, window.innerWidth - POPOUT_WIDTH - VIEWPORT_MARGIN),
		);
		const desiredTop = anchorRect.top - 8;
		const estimatedHeight = 420;
		const top = Math.max(
			VIEWPORT_MARGIN,
			Math.min(desiredTop, window.innerHeight - estimatedHeight - VIEWPORT_MARGIN),
		);
		return {
			position: 'fixed',
			left,
			top,
			width: POPOUT_WIDTH,
			borderColor: accent,
			boxShadow: `0 16px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px ${accent}55, 0 0 28px ${accent}30`,
		};
	}, [anchorRect, accent]);

	const displayName = fullUser?.displayName || member.displayName;
	const username = fullUser?.username || member.displayName;
	const avatarUrl = fullUser?.avatarUrl ?? member.avatarUrl ?? null;
	const aboutMe = fullUser?.aboutMe?.trim();
	// Resolve presence against the live heartbeat set so the popout
	// matches what the sidebar / member list show for this user.
	const { resolveStatus } = useOnlineUsers();
	const storedStatus = fullUser?.status ?? member.status ?? 'offline';
	const liveStatus = resolveStatus(storedStatus, member.userId);
	const presence = mapPresence(liveStatus);
	const isMe = localUserId === member.userId;

	return createPortal(
		<div
			ref={cardRef}
			className={styles.card}
			style={positionStyle}
			onClick={(e) => e.stopPropagation()}
		>
			{/* Banner — solid accent color. */}
			<div
				className={styles.banner}
				style={{ backgroundColor: accent }}
			/>

			<div className={styles.avatarWrap}>
				<Avatar
					src={avatarUrl}
					fallback={displayName}
					size={80}
					status={presence}
				/>
			</div>

			<div className={styles.body}>
				<div className={styles.nameBlock}>
					<div className={styles.displayName} title={displayName}>
						{displayName}
					</div>
					<div className={styles.handle} title={username}>
						{username}
					</div>
				</div>

				{aboutMe && (
					<>
						<div className={styles.divider} />
						<div className={styles.section}>
							<div className={styles.sectionLabel}>About Me</div>
							<div className={styles.bioText}>{aboutMe}</div>
						</div>
					</>
				)}

				{isMe && onOpenProfile && (
					<>
						<div className={styles.divider} />
						<Button
							variant="primary"
							size="sm"
							fitContainer
							icon={<PencilSimple size={16} />}
							onClick={() => {
								onOpenProfile();
								onClose();
							}}
						>
							Edit Profile
						</Button>
					</>
				)}

				{!isMe && canManageRoles && onOpenRoles && (
					<>
						<div className={styles.divider} />
						<Button
							variant="secondary"
							size="sm"
							fitContainer
							icon={<ShieldCheck size={16} />}
							onClick={() => {
								onOpenRoles();
								onClose();
							}}
						>
							Manage Roles
						</Button>
					</>
				)}

				{!isMe && onRotateKey && (
					<>
						<div className={styles.divider} />
						<Button
							variant="secondary"
							size="sm"
							fitContainer
							icon={<Key size={16} />}
							loading={rotating}
							onClick={async () => {
								if (rotating) return;
								setRotating(true);
								setRotateStatus(null);
								try {
									await onRotateKey();
									setRotateStatus({
										type: 'success',
										message: 'Encryption key rotated.',
									});
								} catch (err: any) {
									setRotateStatus({
										type: 'error',
										message: err?.message ?? 'Rotation failed.',
									});
								} finally {
									setRotating(false);
								}
							}}
						>
							Rotate Encryption Key
						</Button>
						{rotateStatus && (
							<div
								style={{
									marginTop: 8,
									fontSize: 12,
									color:
										rotateStatus.type === 'success'
											? '#3ba55d'
											: 'var(--status-danger, #ed4245)',
								}}
							>
								{rotateStatus.message}
							</div>
						)}
					</>
				)}
			</div>
		</div>,
		document.body,
	);
}
