//
// Copyright 2023 DXOS.org
//
import * as Tabs from '@radix-ui/react-tabs';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Format } from '@dxos/echo/internal';
import { log } from '@dxos/log';
import { useClient } from '@dxos/react-client';
import { DynamicTable } from '@dxos/react-ui-table';
import { PanelContainer } from '../../../components';
import { LogTable } from './LogTable';
import { MetricsView } from './MetricsView';
import { TraceView } from './TraceView';
export const TracingPanel = () => {
    const client = useClient();
    // Store state using useState instead of ref
    const [state, setState] = useState({
        resources: new Map(),
        spans: new Map(),
    });
    const [live, setLive] = useState(true);
    const [selectedResourceId, setSelectedResourceId] = useState();
    const selectedResource = selectedResourceId !== undefined ? state.resources.get(selectedResourceId) : undefined;
    useEffect(() => {
        const stream = client.services.services.TracingService.streamTrace();
        stream.subscribe((data) => {
            if (!live) {
                return;
            }
            setState((prevState) => {
                // Create new map references to trigger re-render
                const newResources = new Map(prevState.resources);
                const newSpans = new Map(prevState.spans);
                for (const event of data.resourceAdded ?? []) {
                    const existing = newResources.get(event.resource.id);
                    if (!existing) {
                        newResources.set(event.resource.id, { resource: event.resource, spans: [], logs: [] });
                    }
                    else {
                        existing.resource = event.resource;
                    }
                }
                for (const event of data.resourceRemoved ?? []) {
                    newResources.delete(event.id);
                }
                for (const event of data.spanAdded ?? []) {
                    newSpans.set(event.span.id, event.span);
                    if (event.span.parentId === undefined) {
                        const resource = newResources.get(event.span.resourceId);
                        if (resource) {
                            resource.spans.push(event.span);
                        }
                    }
                }
                for (const event of data.logAdded ?? []) {
                    const resource = newResources.get(event.log.meta.resourceId);
                    if (!resource) {
                        return prevState; // No changes
                    }
                    resource.logs.push(event.log);
                }
                return {
                    resources: newResources,
                    spans: newSpans,
                };
            });
        }, (err) => {
            log.catch(err);
        });
        return () => {
            void stream.close();
        };
    }, [client.services.services.TracingService, live]);
    const containerRef = useRef(null);
    const resourceProperties = useMemo(() => [
        { name: 'name', format: Format.TypeFormat.JSON, size: 200 },
        { name: 'logs', format: Format.TypeFormat.Number, size: 120 },
        { name: 'spans', format: Format.TypeFormat.Number, size: 120 },
        { name: 'info', format: Format.TypeFormat.JSON },
    ], []);
    const rows = useMemo(() => {
        return Array.from(state.resources.values()).map((resourceState) => ({
            id: String(resourceState.resource.id),
            name: resourceState.resource.className,
            logs: resourceState.logs.length,
            spans: resourceState.spans.length,
            info: JSON.stringify(resourceState.resource.info),
        }));
    }, [state.resources]);
    const handleRowClicked = useCallback((row) => {
        if (!row) {
            setSelectedResourceId(undefined);
            return;
        }
        setSelectedResourceId(Number(row.id));
    }, []);
    const features = useMemo(() => ({ selection: { enabled: true, mode: 'single' } }), []);
    // TODO(ZaymonFC): Do we need these visual specializations from the old table?
    //  - 'name' column: Special ResourceName component
    //  - 'info' column: font-mono + text-green-500 styling for JSON
    return (React.createElement(PanelContainer, { classNames: 'grid grid-rows-[1fr_1fr] divide-y divide-separator' },
        React.createElement(DynamicTable, { rows: rows, properties: resourceProperties, features: features, onRowClick: handleRowClicked }),
        React.createElement(Tabs.Root, { defaultValue: 'details', className: 'flex flex-col grow overflow-hidden' },
            React.createElement(Tabs.List, { className: 'flex divide-x divide-separator border-be border-separator' },
                React.createElement(Tabs.Trigger, { className: 'flex-1', value: 'details' }, "Details"),
                React.createElement(Tabs.Trigger, { className: 'flex-1', value: 'logs' }, "Logs"),
                React.createElement(Tabs.Trigger, { className: 'flex-1', value: 'spans' }, "Spans")),
            React.createElement(Tabs.Content, { value: 'details', className: 'grow overflow-auto' },
                React.createElement(MetricsView, { resource: selectedResource?.resource })),
            React.createElement(Tabs.Content, { ref: containerRef, value: 'logs', className: 'grow' },
                React.createElement(LogTable, { logs: selectedResource?.logs ?? [] })),
            React.createElement(Tabs.Content, { value: 'spans', className: 'grow overflow-hidden' },
                React.createElement(TraceView, { state: state, resourceId: selectedResourceId, live: live, onLiveChanged: setLive })))));
};
//# sourceMappingURL=TracingPanel.js.map