pub mod command;
pub mod common;
pub mod editor;
pub mod governance;
pub mod kernel;
pub mod mindmap;
pub mod query;
pub mod tool;

pub use command::{
    CommandEnvelope, CopyTreeDocumentPages, CreateDocumentPage, CreatePage, CreateWorkspace,
    DeleteBlock, DeleteDocumentPage, DuplicateDocumentPage, EmbedBlock, InsertBlock, MoveBlock,
    MoveDocumentPage, PatchBlock, PatchPageBlock, PutMindmap, ReplaceMediaAssetStorage,
    RestoreDocumentPage, SavePageContent, UpdateBlock, UpdatePageOptions, UpdatePageStats,
    UpdatePageTitle,
};
pub use common::{
    ActorPayload, AffectedObject, ErrorDetail, ErrorPayload, OkPayload, RequestMeta, ResponseMeta,
    SourcePayload, TargetRef,
};
pub use editor::{
    BlockProps, ContentNode, ContentNodePayload, EditorAttachReferenceToken, EditorBlock,
    EditorBlockDocument, EditorBlockType, EditorCommand, EditorCommandCatalog,
    EditorCommandDescriptor, EditorCommandKind, EditorDeleteBlock, EditorDetachReferenceToken,
    EditorIndentBlock, EditorInsertBlockAfter, EditorKernelCommandMapping, EditorMergeWithPrevious,
    EditorMoveBlock, EditorOutdentBlock, EditorReplaceBlock, EditorSplitBlock,
    EditorToggleHeadingCollapse, MarkdownExportBoundary, MarkdownExportMode, MarkdownExportOptions,
    MarkdownExportRequest, MarkdownExportResult, MarkdownFlavor, MarkdownImportBoundary,
    MarkdownImportMode, MarkdownImportOptions, MarkdownImportRequest, MarkdownImportResult,
    ReferenceToken, ReferenceTokenKind, ReferenceTokenStrategy, TextMark,
};
pub use kernel::{
    DocumentContentResult, DocumentReadEvidenceItem, DocumentReadEvidenceKind, DocumentReadNode,
    DocumentReadNodeMeta, DocumentReadNodeType, DocumentReadOutlineEntry, DocumentReadPageSubtree,
    DocumentReadStats, DocumentReadSubtree, KernelAttachEdge, KernelAuditStamp,
    KernelContentPayload, KernelCreateNode, KernelDetachEdge, KernelEdge, KernelEdgeListResult,
    KernelEdgeType, KernelGetNode, KernelGetSubtree, KernelGraphDirection,
    KernelGraphTraversalResult, KernelGraphVisit, KernelListChildren, KernelListEdges,
    KernelMoveSubtree, KernelNode, KernelNodeMetadata, KernelNodeType, KernelProjectionAssetKind,
    KernelProjectionCapability, KernelProjectionFilter, KernelProjectionItem, KernelProjectionKind,
    KernelProjectionRequest, KernelProjectionResourceKind, KernelProjectionResourceMeta,
    KernelProjectionResult, KernelProjectionRowKind, KernelRefsPayload, KernelSubtreeRef,
    KernelSubtreeResult, KernelTraverseGraph, KernelUpdateNode,
};
pub use mindmap::{MindmapNodeData, MindmapNodeInput, MindmapNodeRef, MindmapOp, MindmapTreeNode};
pub use query::{
    GetBlock, GetBridgeCommand, GetBridgeRequest, GetBridgeTrace, GetMindmap, GetPage,
    GetPageContent, GetPageMeta, ListBridgeWorkspaceOverview, ListPageBlocks, ListSidebarDataset,
    QueryEnvelope, SearchBlocks, SearchDocuments, SearchPages, SearchRecent,
};
pub use tool::{
    default_tool_registry, invocation_kind_label, tool_effect_label, tool_mode_label,
    InvocationKind, ToolEffect, ToolExecutionMode, ToolInvocation, ToolRegistry, ToolSetSpec,
    ToolSpec, BRIDGE_TOOL_COMMAND_GET, BRIDGE_TOOL_REQUEST_GET, BRIDGE_TOOL_TRACE_GET,
    DOCS_TOOLSET_READ, DOCS_TOOL_READ, DOCS_TOOL_SEARCH, DOC_TOOLSET_READ, DOC_TOOLSET_WRITE,
    DOC_TOOL_FIND, DOC_TOOL_GET, DOC_TOOL_INSERT_BLOCKS, DOC_TOOL_REPLACE_RANGE,
    INDEX_TOOL_REBUILD, MINDMAP_TOOLSET_READ, MINDMAP_TOOLSET_WRITE, MINDMAP_TOOL_APPLY_OPS,
    MINDMAP_TOOL_EMPTY_TRASH, MINDMAP_TOOL_EXPAND_NODE, MINDMAP_TOOL_GET, MINDMAP_TOOL_GET_SUBTREE,
    MINDMAP_TOOL_OUTLINE_TO_MINDMAP, MINDMAP_TOOL_PUT, OBSERVE_TOOLSET_READ,
    ONLYOFFICE_TOOLSET_SERVICE, ONLYOFFICE_TOOL_PREPARE_CALLBACK,
    ONLYOFFICE_TOOL_PREPARE_FORCESAVE, ONLYOFFICE_TOOL_PREPARE_PROXY,
    ONLYOFFICE_TOOL_SESSION_RESOLVE, ONLYOFFICE_TOOL_SIGN, RECOVERY_TOOLSET_JOB,
    REPLAY_TOOL_EVENTS,
};

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn command_envelope_keeps_validate_only_flag() {
        let envelope = CommandEnvelope::<CreateWorkspace> {
            name: "create_workspace".into(),
            command_id: "cmd_1".into(),
            idempotency_key: Some("idem_1".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "cli".into(),
                client: "mnote-cli".into(),
            },
            target: None,
            payload: CreateWorkspace {
                name: "demo".into(),
                slug: Some("demo".into()),
            },
            reason: Some("初始化工作区".into()),
            refs: vec![],
            dry_run: false,
            validate_only: true,
        };

        assert!(envelope.validate_only);
    }

    #[test]
    fn default_tool_registry_exposes_doc_tools() {
        let registry = default_tool_registry();
        assert_eq!(
            registry.tool_names(),
            vec![
                "search_web",
                "doc_get",
                "doc_find",
                "docs_search",
                "docs_read",
                "image_read",
                "doc_insert_blocks",
                "doc_replace_range",
                "slash_run",
                "mindmap_get",
                "mindmap_get_subtree",
                "mindmap_put",
                "mindmap_apply_ops",
                "mindmap_expand_node",
                "mindmap_empty_trash",
                "mindmap_outline_to_mindmap",
                "bridge_request_get",
                "bridge_trace_get",
                "bridge_command_get",
                "event_replay",
                "index_rebuild",
                "onlyoffice_session_resolve",
                "onlyoffice_sign",
                "onlyoffice_prepare_proxy",
                "onlyoffice_prepare_callback",
                "onlyoffice_prepare_forcesave",
            ]
        );
        assert_eq!(
            registry
                .tool("search_web")
                .expect("search_web should exist")
                .toolset_id,
            "toolset.readonly"
        );
        assert_eq!(
            registry
                .tool("image_read")
                .expect("image_read should exist")
                .toolset_id,
            "toolset.media_read"
        );
        assert_eq!(
            registry
                .tool("slash_run")
                .expect("slash_run should exist")
                .toolset_id,
            "toolset.slash_write"
        );
        let readonly = registry
            .toolset("toolset.readonly")
            .expect("readonly toolset should exist");
        assert!(!readonly.write_toolset);
        assert_eq!(readonly.tool_names, &["search_web"]);
        let media = registry
            .toolset("toolset.media_read")
            .expect("media toolset should exist");
        assert!(!media.write_toolset);
        assert_eq!(media.tool_names, &["image_read"]);
        let slash = registry
            .toolset("toolset.slash_write")
            .expect("slash toolset should exist");
        assert!(slash.write_toolset);
        assert_eq!(slash.tool_names, &["slash_run"]);
        let docs_read = registry
            .toolset("toolset.docs_read")
            .expect("docs_read toolset should exist");
        assert!(!docs_read.write_toolset);
        assert_eq!(docs_read.tool_names, &["docs_search", "docs_read"]);
        let doc_write = registry
            .toolset("toolset.doc_write")
            .expect("doc_write toolset should exist");
        assert!(doc_write.write_toolset);
        assert_eq!(
            doc_write.tool_names,
            &["doc_insert_blocks", "doc_replace_range"]
        );
        assert_eq!(
            registry
                .tool("doc_get")
                .expect("doc_get should exist")
                .toolset_id,
            "toolset.doc_read"
        );
        let mindmap_write = registry
            .toolset("toolset.mindmap_write")
            .expect("mindmap_write toolset should exist");
        assert!(mindmap_write.write_toolset);
        assert_eq!(
            mindmap_write.tool_names,
            &[
                "mindmap_put",
                "mindmap_apply_ops",
                "mindmap_expand_node",
                "mindmap_empty_trash",
                "mindmap_outline_to_mindmap",
            ]
        );
        let onlyoffice_service = registry
            .toolset("toolset.onlyoffice_service")
            .expect("onlyoffice service toolset should exist");
        assert!(onlyoffice_service.write_toolset);
        assert_eq!(
            onlyoffice_service.tool_names,
            &[
                "onlyoffice_session_resolve",
                "onlyoffice_sign",
                "onlyoffice_prepare_proxy",
                "onlyoffice_prepare_callback",
                "onlyoffice_prepare_forcesave",
            ]
        );
        let observe = registry
            .toolset("toolset.observe_read")
            .expect("observe toolset should exist");
        assert!(!observe.write_toolset);
        assert_eq!(
            observe.tool_names,
            &[
                "bridge_request_get",
                "bridge_trace_get",
                "bridge_command_get"
            ]
        );
        let recovery = registry
            .toolset("toolset.recovery_job")
            .expect("recovery toolset should exist");
        assert!(recovery.write_toolset);
        assert_eq!(recovery.tool_names, &["event_replay", "index_rebuild"]);
    }
}
