//
// Copyright 2020 DXOS.org
//
import * as SchemaAST from 'effect/SchemaAST';
import React, { useMemo, useState } from 'react';
import { ComputeGraph, ComputeGraphModel, WorkflowLoader } from '@dxos/conductor';
import { Format } from '@dxos/echo/internal';
import { Filter } from '@dxos/echo-db';
import { DXN } from '@dxos/keys';
import { useQuery } from '@dxos/react-client/echo';
import { Toolbar } from '@dxos/react-ui';
import { mx } from '@dxos/ui-theme';
import { ControlledSelector, MasterDetailTable, PanelContainer } from '../../../components';
import { DataSpaceSelector } from '../../../containers';
import { useDevtoolsState } from '../../../hooks';
import { WorkflowDebugPanel, WorkflowDebugPanelMode } from './WorkflowDebugPanel';
export const WorkflowPanel = (props) => {
    const state = useDevtoolsState();
    const space = props.space ?? state.space;
    const [displayMode, setDisplayMode] = useState(DisplayMode.COMPILED);
    const [executionMode, setExecutionMode] = useState(WorkflowDebugPanelMode.LOCAL);
    const graphs = useQuery(space?.db, Filter.type(ComputeGraph));
    const [selectedId, setSelectedId] = useState();
    const selected = useMemo(() => graphs.find((graph) => graph.id === selectedId), [graphs, selectedId]);
    const loader = useMemo(() => createLoader(graphs), [graphs]);
    const properties = useMemo(() => [
        { name: 'id', format: Format.TypeFormat.String },
        { name: 'nodes', format: Format.TypeFormat.Number, size: 100 },
        { name: 'edges', format: Format.TypeFormat.Number, size: 100 },
    ], []);
    const tableData = useMemo(() => {
        return graphs.map((graph) => ({
            id: graph.id,
            nodes: graph.graph.nodes.length,
            edges: graph.graph.edges.length,
            _original: graph,
        }));
    }, [graphs]);
    const detailsTransform = useMemo(() => {
        return async (data) => {
            const graph = data._original;
            if (!graph) {
                return null;
            }
            try {
                if (displayMode === DisplayMode.COMPILED) {
                    return await toWorkflow(loader, graph);
                }
                else if (displayMode === DisplayMode.GRAPH) {
                    return toCompactGraph(graph);
                }
                else {
                    // RAW mode - show the original graph
                    return graph;
                }
            }
            catch (err) {
                return { error: err.message, stack: err.stack };
            }
        };
    }, [loader, displayMode]);
    return (React.createElement(PanelContainer, { toolbar: React.createElement(Toolbar.Root, null,
            !props.space && React.createElement(DataSpaceSelector, null),
            React.createElement(ControlledSelector, { values: Object.values(DisplayMode), value: displayMode, setValue: setDisplayMode }),
            React.createElement(ControlledSelector, { values: Object.values(WorkflowDebugPanelMode), value: executionMode, setValue: setExecutionMode })) },
        React.createElement("div", { className: 'bs-full grid grid-rows-[4fr_3fr]' },
            React.createElement(MasterDetailTable, { properties: properties, data: tableData, detailsTransform: detailsTransform, onSelectionChanged: setSelectedId }),
            React.createElement("div", { className: mx('bs-full') }, selected && React.createElement(WorkflowDebugPanel, { loader: loader, graph: selected, mode: executionMode })))));
};
const toWorkflow = async (loader, graph) => {
    try {
        const loaded = await loader.load(DXN.fromLocalObjectId(graph.id));
        const mapProps = (ast) => Object.fromEntries(SchemaAST.getPropertySignatures(ast).map((prop) => [prop.name, prop.type]));
        const workflowMeta = loaded.resolveMeta();
        return {
            compiled: true,
            inputs: workflowMeta.inputs.map((input) => [input.nodeId, mapProps(input.schema.ast)]),
            outputs: workflowMeta.outputs.map((output) => [output.nodeId, mapProps(output.schema.ast)]),
        };
    }
    catch (err) {
        return { message: err.message, stack: err.stack };
    }
};
const toCompactGraph = (graph) => {
    const model = new ComputeGraphModel(graph);
    const result = {};
    for (const node of model.nodes) {
        const incoming = [];
        const outgoing = [];
        for (const edge of model.edges) {
            if (node.id === edge.source) {
                outgoing.push(`${edge.output} -> ${edge.target}.${edge.input}`);
            }
            else if (node.id === edge.target) {
                incoming.push(`${edge.source}.${edge.output} -> ${edge.input}`);
            }
        }
        result[node.id] = { in: incoming, out: outgoing };
    }
    return result;
};
const createLoader = (graphs) => new WorkflowLoader({
    graphLoader: async (graphDxn) => {
        const graph = graphs.find((g) => DXN.equals(graphDxn, DXN.fromLocalObjectId(g.id)));
        if (!graph) {
            throw new Error(`Graph not found: ${graphDxn}.`);
        }
        return graph;
    },
    nodeResolver: async (node) => {
        throw new Error(`Unknown node type: ${node.type}.`);
    },
});
var DisplayMode;
(function (DisplayMode) {
    DisplayMode["COMPILED"] = "compiled";
    DisplayMode["GRAPH"] = "graph";
    DisplayMode["RAW"] = "raw";
})(DisplayMode || (DisplayMode = {}));
//# sourceMappingURL=WorkflowPanel.js.map