import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/*
 * Copyright (c) 2023-2025 Datalayer, Inc.
 * Distributed under the terms of the Modified BSD License.
 */
/**
 * UserBadge – Shows the authenticated user's display name.
 *
 * On hover, reveals a JWT details popover with email, handle, UID,
 * issued/expiry timestamps, roles, and the raw decoded claims.
 *
 * The trigger text and the popover share a single container so the
 * popover stays open while the mouse travels from the label into it.
 *
 * @module views/profile
 */
import { useState, useRef, useCallback } from 'react';
import { Box, Text } from '@primer/react';
import { parseJwtPayload, getDatalayerJwtUser, getDatalayerDisplayName, } from '../../utils/Jwt.js';
import { getRelativeTime } from '../../utils/Date.js';
// ── Component ─────────────────────────────────────────────────────
export const UserBadge = ({ token, variant = 'full', showExpandToggle = true, expirationWarningMs = 60 * 60 * 1000, }) => {
    const [open, setOpen] = useState(false);
    const [expanded, setExpanded] = useState(false);
    const closeTimer = useRef(null);
    const handleEnter = useCallback(() => {
        if (closeTimer.current)
            clearTimeout(closeTimer.current);
        setOpen(true);
    }, []);
    const handleLeave = useCallback(() => {
        // Small delay so the mouse can travel from the label into the popover
        // without it closing.
        closeTimer.current = setTimeout(() => setOpen(false), 120);
    }, []);
    const user = getDatalayerJwtUser(token);
    const displayName = getDatalayerDisplayName(user, user?.handle ?? '');
    const claims = parseJwtPayload(token);
    // Colour the trigger label based on token expiry:
    // - red when already expired,
    // - yellow when expiring within ``expirationWarningMs``,
    // - muted grey otherwise.
    const msUntilExpiry = claims?.exp
        ? claims.exp * 1000 - Date.now()
        : undefined;
    const expired = msUntilExpiry !== undefined && msUntilExpiry <= 0;
    const expiringSoon = msUntilExpiry !== undefined &&
        msUntilExpiry > 0 &&
        msUntilExpiry <= expirationWarningMs;
    const triggerColor = expired
        ? 'danger.fg'
        : expiringSoon
            ? 'attention.fg'
            : 'fg.muted';
    return (_jsxs(Box, { sx: { position: 'relative' }, onMouseEnter: handleEnter, onMouseLeave: handleLeave, children: [_jsx(Text, { sx: {
                    fontSize: 1,
                    color: triggerColor,
                    cursor: 'default',
                    borderBottom: '1px dashed',
                    borderColor: 'border.muted',
                    pb: '1px',
                    userSelect: 'none',
                }, children: displayName }), open && claims && (_jsxs(Box, { sx: {
                    position: 'absolute',
                    top: 'calc(100% + 4px)',
                    right: 0,
                    zIndex: 100,
                    width: '400px',
                    bg: 'canvas.overlay',
                    border: '1px solid',
                    borderColor: 'border.default',
                    borderRadius: 2,
                    boxShadow: 'shadow.large',
                    overflow: 'hidden',
                }, children: [_jsxs(Box, { sx: {
                            px: 3,
                            py: 2,
                            bg: 'canvas.subtle',
                            borderBottom: '1px solid',
                            borderColor: 'border.default',
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'space-between',
                            gap: 2,
                        }, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: "JWT Claims" }), variant === 'small' && showExpandToggle && (_jsx(Box, { as: "button", type: "button", onClick: () => setExpanded(v => !v), "aria-label": expanded ? 'Hide full JWT claims' : 'Show full JWT claims', "aria-expanded": expanded, title: expanded ? 'Hide full JWT claims' : 'Show full JWT claims', sx: {
                                    appearance: 'none',
                                    border: '1px solid',
                                    borderColor: 'border.default',
                                    borderRadius: 1,
                                    bg: 'canvas.default',
                                    color: 'fg.default',
                                    fontSize: 1,
                                    lineHeight: 1,
                                    width: '20px',
                                    height: '20px',
                                    display: 'inline-flex',
                                    alignItems: 'center',
                                    justifyContent: 'center',
                                    cursor: 'pointer',
                                    p: 0,
                                    '&:hover': {
                                        bg: 'canvas.subtle',
                                    },
                                }, children: expanded ? '−' : '+' }))] }), claims.user && (_jsx(Box, { sx: {
                            px: 3,
                            py: 2,
                            borderBottom: '1px solid',
                            borderColor: 'border.muted',
                        }, children: _jsxs(Box, { sx: {
                                display: 'grid',
                                gridTemplateColumns: '90px 1fr',
                                gap: 1,
                                fontSize: 0,
                            }, children: [claims.user.email && (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: claims.user.email })] })), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: claims.user.handle }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontFamily: 'mono', wordBreak: 'break-all' }, children: claims.user.uid }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Issued" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: new Date(claims.iat * 1000).toISOString() }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Expires" }), _jsxs(Box, { sx: {
                                        display: 'flex',
                                        alignItems: 'center',
                                        gap: 2,
                                        minWidth: 0,
                                    }, children: [_jsx(Text, { sx: {
                                                fontFamily: 'mono',
                                                overflow: 'hidden',
                                                textOverflow: 'ellipsis',
                                                whiteSpace: 'nowrap',
                                            }, children: new Date(claims.exp * 1000).toISOString() }), (() => {
                                            const expDate = new Date(claims.exp * 1000);
                                            const msUntilExpiry = expDate.getTime() - Date.now();
                                            const expired = msUntilExpiry <= 0;
                                            const warning = !expired && msUntilExpiry <= expirationWarningMs;
                                            const bg = expired
                                                ? 'danger.subtle'
                                                : warning
                                                    ? 'attention.subtle'
                                                    : 'success.subtle';
                                            const fg = expired
                                                ? 'danger.fg'
                                                : warning
                                                    ? 'attention.fg'
                                                    : 'success.fg';
                                            const border = expired
                                                ? 'danger.muted'
                                                : warning
                                                    ? 'attention.muted'
                                                    : 'success.muted';
                                            return (_jsx(Box, { sx: {
                                                    flexShrink: 0,
                                                    fontSize: 0,
                                                    px: 1,
                                                    py: '1px',
                                                    bg,
                                                    color: fg,
                                                    borderRadius: 1,
                                                    border: '1px solid',
                                                    borderColor: border,
                                                    whiteSpace: 'nowrap',
                                                }, children: getRelativeTime(expDate) }));
                                        })()] })] }) })), (claims.user?.roles ?? claims.roles ?? []).length > 0 && (_jsxs(Box, { sx: {
                            px: 3,
                            py: 2,
                            borderBottom: '1px solid',
                            borderColor: 'border.muted',
                        }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block', mb: 1 }, children: "Roles" }), _jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 1 }, children: (claims.user?.roles ?? claims.roles ?? []).map(r => (_jsx(Box, { sx: {
                                        fontSize: 0,
                                        fontFamily: 'mono',
                                        px: 1,
                                        py: '1px',
                                        bg: 'accent.subtle',
                                        color: 'accent.fg',
                                        borderRadius: 1,
                                        border: '1px solid',
                                        borderColor: 'accent.muted',
                                    }, children: r }, r))) })] })), (variant === 'full' || expanded) && (_jsx(Box, { as: "pre", sx: {
                            m: 0,
                            px: 3,
                            py: 2,
                            fontFamily: 'mono',
                            fontSize: 0,
                            color: 'fg.default',
                            bg: 'canvas.inset',
                            overflow: 'auto',
                            maxHeight: '220px',
                            whiteSpace: 'pre',
                        }, children: JSON.stringify(claims, null, 2) }))] }))] }));
};
export default UserBadge;
