import { NodeId, SecretAttrValue, BindableAttrValues, BindableAttrEntries, NodeReference, BindableAttrValue, NodeHashes } from '@mui/toolpad-core';
import { ThemeOptions, BoxProps } from '@mui/material';

type AppDomNodeType = 'app' | 'connection' | 'theme' | 'page' | 'element' | 'query' | 'mutation';
interface AppDomNodeBase {
    readonly id: NodeId;
    readonly type: AppDomNodeType;
    readonly name: string;
    readonly parentId: NodeId | null;
    readonly parentProp: string | null;
    readonly parentIndex: string | null;
    readonly attributes: {};
}
interface AppNode extends AppDomNodeBase {
    readonly type: 'app';
    readonly parentId: null;
    readonly attributes: {
        readonly authorization?: {
            readonly roles?: {
                readonly name: string;
                readonly description?: string;
            }[];
        };
    };
}
interface ThemeNode extends AppDomNodeBase {
    readonly type: 'theme';
    readonly theme?: ThemeOptions;
}
interface ConnectionNode<P = unknown> extends AppDomNodeBase {
    readonly type: 'connection';
    readonly attributes: {
        readonly dataSource: string;
        readonly params: SecretAttrValue<P | null>;
        readonly status: ConnectionStatus | null;
    };
}
type PageDisplayMode = 'standalone' | 'shell';
interface PageNode extends AppDomNodeBase {
    readonly type: 'page';
    readonly attributes: {
        readonly title?: string;
        readonly alias?: string[];
        readonly parameters?: [string, string][];
        readonly module?: string;
        readonly display?: PageDisplayMode;
        readonly codeFile?: boolean;
        readonly displayName?: string;
        readonly authorization?: {
            readonly allowAll?: boolean;
            readonly allowedRoles?: string[];
        };
    };
}
interface ElementNode<P = any> extends AppDomNodeBase {
    readonly type: 'element';
    readonly attributes: {
        readonly component: string;
    };
    readonly props?: BindableAttrValues<P>;
    readonly layout?: {
        readonly horizontalAlign?: BoxProps['justifyContent'];
        readonly verticalAlign?: BoxProps['alignItems'];
        readonly columnSize?: number;
    };
}
type FetchMode = 'query' | 'mutation';
/**
 * A DOM query is defined primarily by a server defined part "attributes.query"
 * and a clientside defined part "params". "params" are constructed in the runtime
 * from bound expressions. The resolved object will be sent to the server and combined
 * with the query will be used to collect the data from the backend.
 */
interface QueryNode<Q = any> extends AppDomNodeBase {
    readonly type: 'query';
    readonly params?: BindableAttrEntries;
    readonly attributes: {
        readonly mode?: FetchMode;
        readonly dataSource?: string;
        readonly connectionId: NodeReference | null;
        readonly query: Q;
        readonly transform?: string;
        readonly transformEnabled?: boolean;
        /** @deprecated Not necessary to be user-facing, we will expose staleTime instead if necessary */
        readonly refetchOnWindowFocus?: boolean;
        /** @deprecated Not necessary to be user-facing, we will expose staleTime instead if necessary */
        readonly refetchOnReconnect?: boolean;
        readonly refetchInterval?: number;
        readonly cacheTime?: number;
        readonly enabled?: BindableAttrValue<boolean>;
    };
}
/**
 * @deprecated QueryNode can act as a mutation by switching the `mode` attribute to 'mutation'
 */
interface MutationNode<Q = any> extends AppDomNodeBase {
    readonly type: 'mutation';
    readonly params?: BindableAttrValues;
    readonly attributes: {
        readonly dataSource?: string;
        readonly connectionId: NodeReference | null;
        readonly query: Q;
    };
}
type AppDomNodeOfType<K extends AppDomNodeType> = {
    app: AppNode;
    connection: ConnectionNode;
    theme: ThemeNode;
    page: PageNode;
    element: ElementNode;
    query: QueryNode;
    mutation: MutationNode;
}[K];
type AppDomNode = AppDomNodeOfType<AppDomNodeType>;
type AppDomNodes = Record<NodeId, AppDomNode>;
interface AppDom {
    nodes: AppDomNodes;
    root: NodeId;
    version?: number;
}
declare const RENDERTREE_NODES: readonly ["app", "page", "element", "query", "mutation", "theme"];
type RenderTreeNodeType = (typeof RENDERTREE_NODES)[number];
type RenderTreeNode = {
    [K in RenderTreeNodeType]: AppDomNodeOfType<K>;
}[RenderTreeNodeType];
type RenderTreeNodes = Record<NodeId, RenderTreeNode>;
interface RenderTree {
    root: NodeId;
    nodes: RenderTreeNodes;
    version?: number;
}

/**
 * Defines all the data needed to render the runtime.
 * While the dom is optimized for storage and editing. It isn't the ideal format used to render the application
 * `RuntimeData` will hold all data to render a toolpad app and will contain things like:
 * - precompile assets, like code component modules
 * - precompiled expressions
 * - datastructures optimized for rendering with less processing required
 * - ...
 */
interface RuntimeState {
    dom: RenderTree;
}

declare global {
    interface Error {
        code?: unknown;
    }
}
interface ConnectionStatus {
    timestamp: number;
    error?: string;
}
interface AppCanvasState extends RuntimeState {
    savedNodes: NodeHashes;
}

export type { AppCanvasState as A, PageNode as P, RuntimeState as R, AppDom as a };
