import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/*
 * Copyright (c) 2023-2025 Datalayer, Inc.
 * Distributed under the terms of the Modified BSD License.
 */
/**
 * OtelTracesList – Tabular list of spans with Time / Message / Scope / Duration
 * columns, using Primer React components for consistent theming.
 *
 * Spans that share the same trace_id are grouped into collapsible trees:
 * only root spans are shown initially; clicking a row with children
 * expands / collapses the nested child rows (shown indented).
 *
 * @module otel/OtelTracesList
 */
import { useMemo, useCallback, useState } from 'react';
import { Box, Text, Label, Spinner } from '@primer/react';
import { Blankslate } from '@primer/react/experimental';
import { TelescopeIcon, ChevronRightIcon, ChevronDownIcon, } from '@primer/octicons-react';
import { formatDuration, formatTime, buildSpanTree } from '../utils.js';
const GRID_COLS = '140px 1fr 160px 90px';
// ── Helpers ─────────────────────────────────────────────────────────
/** Extract gen_ai token counts from span attributes. */
function getTokenUsage(span) {
    const attrs = span.attributes;
    if (!attrs)
        return null;
    const input = attrs['gen_ai.usage.input_tokens'] != null
        ? Number(attrs['gen_ai.usage.input_tokens'])
        : undefined;
    const output = attrs['gen_ai.usage.output_tokens'] != null
        ? Number(attrs['gen_ai.usage.output_tokens'])
        : undefined;
    if (input == null && output == null)
        return null;
    return { input, output };
}
export const OtelTracesList = ({ spans, loading, selectedSpanId, onSelectSpan, }) => {
    // Set of expanded span_ids (show their children)
    const [expanded, setExpanded] = useState(new Set());
    // Build the span tree from flat input
    const roots = useMemo(() => buildSpanTree(spans), [spans]);
    // Flatten visible rows based on which nodes are expanded
    const visibleRows = useMemo(() => {
        const rows = [];
        function walk(node, depth) {
            const children = node.children ?? [];
            rows.push({ span: node, depth, hasChildren: children.length > 0 });
            if (expanded.has(node.span_id)) {
                for (const child of children) {
                    walk(child, depth + 1);
                }
            }
        }
        for (const root of roots) {
            walk(root, 0);
        }
        return rows;
    }, [roots, expanded]);
    const toggleExpand = useCallback((spanId) => {
        setExpanded(prev => {
            const next = new Set(prev);
            if (next.has(spanId)) {
                next.delete(spanId);
            }
            else {
                next.add(spanId);
            }
            return next;
        });
    }, []);
    if (loading) {
        return (_jsx(Box, { sx: { display: 'flex', justifyContent: 'center', p: 5 }, children: _jsx(Spinner, { size: "medium" }) }));
    }
    if (spans.length === 0) {
        return (_jsxs(Blankslate, { children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: 24 }) }), _jsx(Blankslate.Heading, { children: "No traces found" }), _jsx(Blankslate.Description, { children: "Send some telemetry data first." })] }));
    }
    return (_jsxs(Box, { sx: { width: '100%', flex: 1, minHeight: 0, overflow: 'auto' }, children: [_jsx(Box, { sx: {
                    display: 'grid',
                    gridTemplateColumns: GRID_COLS,
                    gap: 2,
                    px: 3,
                    position: 'sticky',
                    top: 0,
                    bg: 'canvas.subtle',
                    zIndex: 1,
                    borderBottom: '2px solid',
                    borderColor: 'border.default',
                }, children: ['Time', 'Message', 'Scope', 'Duration'].map(h => (_jsx(Text, { sx: {
                        fontWeight: 'bold',
                        fontSize: 0,
                        color: 'fg.muted',
                        textTransform: 'uppercase',
                        letterSpacing: '0.05em',
                        py: 2,
                        ...(h === 'Duration' ? { textAlign: 'right' } : {}),
                    }, children: h }, h))) }), visibleRows.map(({ span, depth, hasChildren }, idx) => {
                const isSelected = selectedSpanId === span.span_id;
                const isExpanded = expanded.has(span.span_id);
                const indent = depth * 20;
                return (_jsxs(Box, { onClick: () => {
                        if (hasChildren) {
                            toggleExpand(span.span_id);
                        }
                        onSelectSpan?.(span);
                    }, sx: {
                        display: 'grid',
                        gridTemplateColumns: GRID_COLS,
                        gap: 2,
                        px: 3,
                        py: '5px',
                        cursor: 'pointer',
                        bg: isSelected
                            ? 'accent.subtle'
                            : depth > 0
                                ? 'canvas.inset'
                                : 'canvas.default',
                        borderBottom: '1px solid',
                        borderColor: 'border.muted',
                        ':hover': {
                            bg: isSelected ? 'accent.subtle' : 'canvas.subtle',
                        },
                    }, children: [_jsx(Text, { sx: {
                                fontSize: 1,
                                fontFamily: 'mono',
                                color: 'fg.muted',
                                whiteSpace: 'nowrap',
                                lineHeight: '22px',
                            }, children: formatTime(span.start_time) }), _jsxs(Box, { sx: {
                                display: 'flex',
                                alignItems: 'center',
                                gap: 1,
                                overflow: 'hidden',
                                lineHeight: '22px',
                                pl: `${indent}px`,
                            }, children: [hasChildren ? (_jsx(Box, { sx: {
                                        flexShrink: 0,
                                        color: 'fg.muted',
                                        display: 'flex',
                                        alignItems: 'center',
                                    }, children: isExpanded ? (_jsx(ChevronDownIcon, { size: 14 })) : (_jsx(ChevronRightIcon, { size: 14 })) })) : depth > 0 ? (
                                /* Connector dash for child leaves */
                                _jsx(Box, { sx: {
                                        flexShrink: 0,
                                        width: '14px',
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'center',
                                        color: 'fg.subtle',
                                        fontSize: 0,
                                    }, children: "\u2500" })) : null, _jsx(Text, { sx: {
                                        fontSize: 1,
                                        overflow: 'hidden',
                                        textOverflow: 'ellipsis',
                                        whiteSpace: 'nowrap',
                                    }, title: span.span_name, children: span.span_name }), span.status_code === 'ERROR' && (_jsx(Label, { variant: "danger", size: "small", children: "ERROR" })), (() => {
                                    const usage = getTokenUsage(span);
                                    if (!usage)
                                        return null;
                                    return (_jsxs(Box, { sx: {
                                            display: 'inline-flex',
                                            alignItems: 'center',
                                            gap: '2px',
                                            border: '1px solid',
                                            borderColor: 'border.default',
                                            borderRadius: 2,
                                            px: 1,
                                            fontSize: '10px',
                                            fontFamily: 'mono',
                                            color: 'fg.muted',
                                            flexShrink: 0,
                                            lineHeight: '16px',
                                        }, children: [usage.input != null && (_jsxs(Box, { sx: {
                                                    display: 'inline-flex',
                                                    alignItems: 'center',
                                                    gap: '1px',
                                                }, children: [_jsx(Text, { sx: { fontSize: '9px', color: 'fg.subtle' }, children: "\u2197" }), _jsx(Text, { children: usage.input })] })), usage.output != null && (_jsxs(Box, { sx: {
                                                    display: 'inline-flex',
                                                    alignItems: 'center',
                                                    gap: '1px',
                                                }, children: [_jsx(Text, { sx: { fontSize: '9px', color: 'fg.subtle' }, children: "\u2199" }), _jsx(Text, { children: usage.output })] }))] }));
                                })(), span.otel_scope_name && (_jsx(Label, { size: "small", variant: "secondary", sx: { flexShrink: 0, fontSize: '10px' }, children: span.otel_scope_name }))] }), _jsx(Text, { sx: {
                                fontSize: 1,
                                color: 'fg.muted',
                                overflow: 'hidden',
                                textOverflow: 'ellipsis',
                                whiteSpace: 'nowrap',
                                lineHeight: '22px',
                            }, title: `${span.service_name} / ${span.otel_scope_name ?? ''}`, children: span.service_name }), _jsx(Text, { sx: {
                                fontSize: 1,
                                fontFamily: 'mono',
                                textAlign: 'right',
                                lineHeight: '22px',
                                color: span.duration_ms != null && span.duration_ms > 1000
                                    ? 'danger.fg'
                                    : 'fg.default',
                            }, children: formatDuration(span.duration_ms) })] }, `${span.trace_id}-${span.span_id}-${idx}`));
            })] }));
};
