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.
 */
/**
 * OtelMetricsList – Tabular view of metric data points grouped by
 * metric name, with expandable rows showing individual data points.
 *
 * Uses Primer React components for consistent theming.
 *
 * @module otel/OtelMetricsList
 */
import { useMemo, useState } from 'react';
import { Box, Text, Label, Spinner, CounterLabel, SegmentedControl, } from '@primer/react';
import { Blankslate } from '@primer/react/experimental';
import { MeterIcon, ChevronDownIcon, ChevronRightIcon, GraphIcon, TableIcon, } from '@primer/octicons-react';
import { formatTime } from '../utils.js';
import { OtelMetricsChart } from './OtelMetricsChart.js';
// ── Helpers ─────────────────────────────────────────────────────────
/** Group metrics by metric_name. */
function groupByName(metrics) {
    const map = new Map();
    for (const m of metrics) {
        const key = m.metric_name || '(unnamed)';
        if (!map.has(key))
            map.set(key, []);
        const group = map.get(key);
        if (group)
            group.push(m);
    }
    return map;
}
/** Format a metric value with optional unit. */
function formatValue(value, unit) {
    const formatted = Number.isInteger(value) ? String(value) : value.toFixed(3);
    return unit ? `${formatted} ${unit}` : formatted;
}
/** Map metric_type to a Primer Label variant. */
function typeVariant(type) {
    switch (type?.toLowerCase()) {
        case 'gauge':
            return 'accent';
        case 'counter':
        case 'sum':
            return 'attention';
        case 'histogram':
            return 'secondary';
        case 'exponentialhistogram':
            return 'success';
        default:
            return 'primary';
    }
}
// ── MetricGroup  ────────────────────────────────────────────────────
const MetricGroup = ({ name, points }) => {
    const [expanded, setExpanded] = useState(false);
    const first = points[0];
    // Compute stats
    const stats = useMemo(() => {
        const values = points.map(p => p.value);
        const min = Math.min(...values);
        const max = Math.max(...values);
        const avg = values.reduce((a, b) => a + b, 0) / values.length;
        const latest = values[values.length - 1];
        const timestamps = points
            .map(p => new Date(p.timestamp).getTime())
            .filter(t => !isNaN(t));
        const startTs = timestamps.length > 0 ? Math.min(...timestamps) : null;
        const endTs = timestamps.length > 0 ? Math.max(...timestamps) : null;
        return { min, max, avg, latest, startTs, endTs };
    }, [points]);
    return (_jsxs(Box, { sx: {
            borderBottom: '1px solid',
            borderColor: 'border.default',
        }, children: [_jsxs(Box, { onClick: () => setExpanded(!expanded), sx: {
                    display: 'grid',
                    gridTemplateColumns: '20px 1fr auto auto auto auto',
                    gap: 3,
                    alignItems: 'center',
                    px: 3,
                    py: 2,
                    cursor: 'pointer',
                    ':hover': { bg: 'canvas.subtle' },
                }, children: [expanded ? (_jsx(ChevronDownIcon, { size: 16 })) : (_jsx(ChevronRightIcon, { size: 16 })), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 0 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: name }), first?.metric_type && (_jsx(Label, { size: "small", variant: typeVariant(first.metric_type), children: first.metric_type })), first?.unit && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["(", first.unit, ")"] }))] }), stats.startTs !== null && stats.endTs !== null && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.subtle', fontFamily: 'mono' }, children: [formatTime(new Date(stats.startTs).toISOString()), stats.startTs !== stats.endTs && (_jsxs(_Fragment, { children: [" \u2192 ", formatTime(new Date(stats.endTs).toISOString())] }))] }))] }), _jsxs(Box, { sx: { textAlign: 'right' }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "latest" }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold', fontFamily: 'mono', ml: 1 }, children: formatValue(stats.latest, first?.unit) })] }), _jsxs(Box, { sx: { textAlign: 'right' }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "avg" }), _jsx(Text, { sx: { fontSize: 1, fontFamily: 'mono', ml: 1 }, children: stats.avg.toFixed(2) })] }), _jsxs(Box, { sx: { textAlign: 'right' }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "min/max" }), _jsxs(Text, { sx: { fontSize: 1, fontFamily: 'mono', ml: 1 }, children: [stats.min.toFixed(1), "\u2013", stats.max.toFixed(1)] })] }), _jsx(CounterLabel, { children: points.length })] }), expanded && (_jsxs(Box, { sx: { bg: 'canvas.subtle' }, children: [_jsxs(Box, { sx: {
                            display: 'grid',
                            gridTemplateColumns: '20px 180px 1fr 140px 160px',
                            gap: 3,
                            px: 3,
                            py: 1,
                            borderTop: '1px solid',
                            borderColor: 'border.muted',
                        }, children: [_jsx(Box, {}), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: "Time" }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: "Service" }), _jsx(Text, { sx: {
                                    fontSize: 0,
                                    fontWeight: 'bold',
                                    color: 'fg.muted',
                                    textAlign: 'right',
                                }, children: "Value" }), _jsx(Text, { sx: {
                                    fontSize: 0,
                                    fontWeight: 'bold',
                                    color: 'fg.muted',
                                    textAlign: 'right',
                                }, children: "Attributes" })] }), points.map((point, idx) => (_jsx(MetricRow, { metric: point }, `${point.timestamp}-${idx}`)))] }))] }));
};
// ── MetricRow ───────────────────────────────────────────────────────
const MetricRow = ({ metric }) => {
    const [showAttrs, setShowAttrs] = useState(false);
    const attrCount = metric.attributes
        ? Object.keys(metric.attributes).length
        : 0;
    return (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
                    display: 'grid',
                    gridTemplateColumns: '20px 180px 1fr 140px 160px',
                    gap: 3,
                    alignItems: 'center',
                    px: 3,
                    py: 1,
                    borderTop: '1px solid',
                    borderColor: 'border.muted',
                    ':hover': { bg: 'canvas.inset' },
                }, children: [_jsx(Box, {}), _jsx(Text, { sx: { fontSize: 0, fontFamily: 'mono', color: 'fg.muted' }, children: formatTime(metric.timestamp) }), _jsx(Text, { sx: { fontSize: 0 }, children: metric.service_name }), _jsx(Text, { sx: {
                            fontSize: 1,
                            fontFamily: 'mono',
                            fontWeight: 'bold',
                            textAlign: 'right',
                        }, children: formatValue(metric.value, metric.unit) }), _jsx(Box, { sx: { textAlign: 'right' }, children: attrCount > 0 ? (_jsxs(Label, { size: "small", variant: "secondary", onClick: (e) => {
                                e.stopPropagation();
                                setShowAttrs(!showAttrs);
                            }, sx: { cursor: 'pointer' }, children: [attrCount, " attr", attrCount !== 1 ? 's' : ''] })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "\u2014" })) })] }), showAttrs && metric.attributes && (_jsx(Box, { sx: { px: 5, py: 2, bg: 'canvas.inset' }, children: _jsx(Box, { as: "pre", sx: {
                        m: 0,
                        fontSize: 0,
                        fontFamily: 'mono',
                        whiteSpace: 'pre-wrap',
                        wordBreak: 'break-word',
                    }, children: JSON.stringify(metric.attributes, null, 2) }) }))] }));
};
// ── OtelMetricsList ─────────────────────────────────────────────────
const COOKIE_KEY = 'otel_metrics_view';
function readViewCookie() {
    try {
        const match = document.cookie.match(/(?:^|;\s*)otel_metrics_view=([^;]+)/);
        if (match && (match[1] === 'chart' || match[1] === 'table'))
            return match[1];
    }
    catch {
        // ignore
    }
    return 'table';
}
function writeViewCookie(v) {
    try {
        document.cookie = `${COOKIE_KEY}=${v};path=/;max-age=31536000`;
    }
    catch {
        // ignore
    }
}
export const OtelMetricsList = ({ metrics, loading = false, }) => {
    const [view, setView] = useState(readViewCookie);
    const handleViewChange = (v) => {
        writeViewCookie(v);
        setView(v);
    };
    const grouped = useMemo(() => groupByName(metrics), [metrics]);
    if (loading) {
        return (_jsx(Box, { sx: {
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                p: 5,
            }, children: _jsx(Spinner, { size: "medium" }) }));
    }
    if (metrics.length === 0) {
        return (_jsxs(Blankslate, { children: [_jsx(Blankslate.Visual, { children: _jsx(MeterIcon, { size: 20 }) }), _jsx(Blankslate.Heading, { children: "No metrics yet" }), _jsx(Blankslate.Description, { children: "Generate some metrics or adjust the filters above." })] }));
    }
    return (_jsxs(Box, { sx: {
            display: 'flex',
            flexDirection: 'column',
            flex: 1,
            minHeight: 0,
            overflow: 'hidden',
        }, children: [_jsx(Box, { sx: {
                    flexShrink: 0,
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'flex-end',
                    px: 3,
                    py: 2,
                    bg: 'canvas.subtle',
                    borderBottom: '1px solid',
                    borderColor: 'border.default',
                    zIndex: 0,
                }, children: _jsxs(SegmentedControl, { "aria-label": "Metrics view", size: "small", onChange: (idx) => handleViewChange(idx === 0 ? 'chart' : 'table'), children: [_jsx(SegmentedControl.IconButton, { icon: GraphIcon, "aria-label": "Chart", selected: view === 'chart' }), _jsx(SegmentedControl.IconButton, { icon: TableIcon, "aria-label": "Table", selected: view === 'table' })] }) }), _jsx(Box, { sx: { flex: 1, minHeight: 0, overflow: 'auto' }, children: view === 'chart' ? (_jsx(Box, { sx: { px: 3, py: 2 }, children: _jsx(OtelMetricsChart, { metrics: metrics, height: 280 }) })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
                                display: 'grid',
                                gridTemplateColumns: '20px 1fr auto auto auto auto',
                                gap: 3,
                                px: 3,
                                py: 1,
                                bg: 'canvas.subtle',
                                borderBottom: '2px solid',
                                borderColor: 'border.default',
                                position: 'sticky',
                                top: 0,
                                zIndex: 1,
                            }, children: [_jsx(Box, {}), ['Metric Name', 'Latest', 'Average', 'Min/Max', 'Points'].map((h, i) => (_jsx(Text, { sx: {
                                        fontSize: 0,
                                        fontWeight: 'bold',
                                        color: 'fg.muted',
                                        textTransform: 'uppercase',
                                        letterSpacing: '0.05em',
                                        textAlign: i === 0 ? undefined : 'right',
                                    }, children: h }, h)))] }), [...grouped.entries()].map(([name, points]) => (_jsx(MetricGroup, { name: name, points: points }, name)))] })) })] }));
};
