//
// Copyright 2023 DXOS.org
//
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Format } from '@dxos/echo/internal';
import { levels, parseFilter } from '@dxos/log';
import { LogLevel } from '@dxos/protocols/proto/dxos/client/services';
import { useClient } from '@dxos/react-client';
import { useStream } from '@dxos/react-client/devtools';
import { Toolbar, useFileDownload } from '@dxos/react-ui';
import { MasterDetailTable, PanelContainer, Searchbar, Select } from '../../../components';
const MAX_LOGS = 2_000;
const defaultEntry = { level: LogLevel.DEBUG, message: '', timestamp: new Date(0) };
const shortFile = (file) => file?.split('/').slice(-1).join('/');
// TODO(wittjosiah): Virtualization.
export const LoggingPanel = () => {
    const client = useClient();
    const loggingService = client?.services?.services?.LoggingService;
    if (!loggingService) {
        return null;
    }
    // Filtering.
    const [text, setText] = useState('');
    // TODO(burdon): Store in context.
    const [query, setQuery] = useState({});
    const handleSearchChange = useCallback((text) => {
        setText(text);
        if (!text) {
            setQuery({});
        }
        setQuery({ filters: parseFilter(text) });
    }, []);
    // Logs.
    // TODO(wittjosiah): `useStream` probably doesn't make sense here.
    const logEntry = useStream(() => loggingService.queryLogs(query), defaultEntry, [query]);
    const [logs, setLogs] = useState([]);
    useEffect(() => {
        if (!logEntry.message) {
            return;
        }
        setLogs((logs) => [...logs.slice(-MAX_LOGS), logEntry]);
    }, [logEntry]);
    const properties = useMemo(() => [
        {
            name: 'timestamp',
            format: Format.TypeFormat.DateTime,
            sort: 'desc',
            size: 194,
        },
        {
            name: 'level',
            format: Format.TypeFormat.SingleSelect,
            size: 100,
            config: {
                options: [
                    { id: 'TRACE', title: 'TRACE', color: 'sky' },
                    { id: 'DEBUG', title: 'DEBUG', color: 'green' },
                    { id: 'VERBOSE', title: 'VERBOSE', color: 'neutral' },
                    { id: 'INFO', title: 'INFO', color: 'blue' },
                    { id: 'WARN', title: 'WARN', color: 'orange' },
                    { id: 'ERROR', title: 'ERROR', color: 'red' },
                ],
            },
        },
        {
            name: 'file',
            format: Format.TypeFormat.String,
            size: 160,
        },
        {
            name: 'message',
            format: Format.TypeFormat.String,
        },
    ], []);
    const tableData = useMemo(() => {
        return logs.map((entry, index) => ({
            id: `${entry.timestamp}-${index}`, // Stable ID based on position and timestamp
            timestamp: entry.timestamp,
            level: Object.entries(levels)
                .find(([, level]) => level === entry.level)?.[0]
                .toUpperCase(),
            file: `${shortFile(entry.meta?.file)}:${entry.meta?.line}`,
            message: entry.message,
            context: entry.context,
        }));
    }, [logs]);
    const presets = useMemo(() => [
        { value: 'trace', label: 'Trace' },
        { value: 'debug', label: 'Debug' },
        { value: 'verbose', label: 'Verbose' },
        { value: 'info', label: 'Info' },
        { value: 'warn', label: 'Warn' },
        { value: 'error', label: 'Error' },
        // TOOD(burdon): Factor out. Move to separate pull down.
        { value: 'info,echo-edge-replicator:debug', label: 'EDGE Replication' },
    ], []);
    const fileDownload = useFileDownload();
    const handleDownload = useCallback(async () => {
        const payload = {
            filters: text,
            logs: logs.map((entry) => entry),
        };
        fileDownload(new Blob([JSON.stringify(payload, undefined, 2)], { type: 'text/plain' }), `${new Date().toISOString().replace(/\W/g, '-')}-logs.json`);
    }, [logs, text, fileDownload]);
    return (React.createElement(PanelContainer, { toolbar: React.createElement(Toolbar.Root, null,
            React.createElement(Select, { items: presets, onValueChange: handleSearchChange }),
            React.createElement(Searchbar, { placeholder: 'Filter (e.g., "info", "client:debug")', value: text, onChange: handleSearchChange }),
            React.createElement(Toolbar.IconButton, { icon: 'ph--download--regular', iconOnly: true, onClick: handleDownload, label: 'Download logs' }),
            React.createElement(Toolbar.IconButton, { icon: 'ph--x--regular', iconOnly: true, onClick: () => setLogs([]), label: 'Clear logs' })) },
        React.createElement(MasterDetailTable, { properties: properties, data: tableData, detailsPosition: 'bottom' })));
};
//# sourceMappingURL=LoggingPanel.js.map