pub mod context;
pub mod mapping;
pub mod read_path;
pub mod types;
pub mod validation;
pub mod write_path;

pub use context::BridgeContext;
pub use mapping::{
    map_command_name_to_convex, map_query_name_to_convex, ConvexMutationRequest, ConvexQueryRequest,
};
pub use read_path::{build_query_request, QueryReadResult};
pub use types::{BridgeError, BridgeErrorKind, BridgeResult};
pub use validation::{validate_command_envelope, validate_query_envelope};
pub use write_path::{
    build_command_log_record, build_domain_event_record, build_write_pipeline, build_write_request,
    WritePipelineResult,
};

#[cfg(test)]
mod tests {
    use super::*;
    use core_protocol::{
        command::{
            CopyTreeDocumentPages, CreateDocumentPage, CreatePage, CreateWorkspace,
            DeleteDocumentPage, DuplicateDocumentPage, MoveDocumentPage, PatchPageBlock,
            PutMindmap, ReplaceMediaAssetStorage, RestoreDocumentPage, SavePageContent,
            UpdatePageOptions, UpdatePageStats, UpdatePageTitle,
        },
        query::{
            GetBlock, GetBridgeCommand, GetBridgeRequest, GetBridgeTrace, GetMindmap, GetPage,
            GetPageContent, GetPageMeta, ListBridgeWorkspaceOverview, ListSidebarDataset,
            SearchDocuments, SearchRecent,
        },
        ActorPayload, CommandEnvelope, QueryEnvelope, SourcePayload, TargetRef,
    };

    fn demo_context() -> BridgeContext {
        BridgeContext {
            deployment_id: Some("dep_1".into()),
            project_id: Some("proj_1".into()),
            request_id: "req_1".into(),
            trace_id: "trace_1".into(),
            actor_type: "human".into(),
            actor_id: "user_1".into(),
            session_id: Some("session_1".into()),
            workspace_id: Some("ws_1".into()),
            tenant_id: Some("tenant_1".into()),
            auth_token: Some("token_1".into()),
            source_channel: "cli".into(),
            source_client: "mnote-cli".into(),
            idempotency_key: Some("idem_ctx".into()),
            validate_only: false,
            dry_run: false,
        }
    }

    #[test]
    fn build_write_request_keeps_workspace_scope() {
        let command = CommandEnvelope {
            name: "create_page".into(),
            command_id: "cmd_1".into(),
            idempotency_key: Some("idem_cmd".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: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: None,
                block_id: None,
            }),
            payload: CreatePage {
                title: "第一页".into(),
                parent_page_id: None,
                position: None,
            },
            reason: Some("初始化页面".into()),
            refs: vec!["spec:phase1-f".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "pages:create");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert_eq!(request.deployment_id.as_deref(), Some("dep_1"));
        assert_eq!(request.project_id.as_deref(), Some("proj_1"));
        assert_eq!(request.idempotency_key.as_deref(), Some("idem_cmd"));
        assert!(request.payload_json.contains("\"kind\":\"command\""));
        assert!(request.payload_json.contains("\"name\":\"create_page\""));
    }

    #[test]
    fn build_query_request_includes_trace_and_workspace() {
        let query = QueryEnvelope {
            name: "get_page".into(),
            payload: GetPage {
                page_id: "page_1".into(),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "pages:get");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert_eq!(request.request_id, "req_1");
        assert_eq!(request.trace_id, "trace_1");
        assert!(request.payload_json.contains("\"kind\":\"query\""));
        assert!(request.payload_json.contains("\"name\":\"get_page\""));
    }

    #[test]
    fn build_write_pipeline_sets_trace_fields() {
        let command = CommandEnvelope {
            name: "create_workspace".into(),
            command_id: "cmd_2".into(),
            idempotency_key: None,
            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: false,
        };

        let pipeline =
            build_write_pipeline(&demo_context(), &command).expect("pipeline should build");
        assert_eq!(pipeline.command_log.command_name, "create_workspace");
        assert!(pipeline
            .command_log
            .payload_summary
            .contains("request_id=req_1"));
        assert_eq!(pipeline.command_log.trace_id, "trace_1");
        assert_eq!(pipeline.command_log.request_id, "req_1");
        assert!(pipeline
            .domain_event
            .payload_json
            .contains("\"trace_id\":\"trace_1\""));
        assert_eq!(pipeline.result.event_ids, vec!["evt_cmd_2".to_string()]);
    }

    #[test]
    fn document_title_command_maps_to_documents_update_title() {
        let command = CommandEnvelope {
            name: "documents.title.update".into(),
            command_id: "cmd_title_1".into(),
            idempotency_key: Some("idem_title".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: UpdatePageTitle {
                page_id: "page_1".into(),
                title: "新标题".into(),
            },
            reason: None,
            refs: vec![],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateTitle");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"documents.title.update\""));
    }

    #[test]
    fn page_head_update_title_command_maps_to_documents_update_title() {
        let command = CommandEnvelope {
            name: "page.head.updateTitle".into(),
            command_id: "cmd_page_title_1".into(),
            idempotency_key: Some("idem_page_title".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: UpdatePageTitle {
                page_id: "page_1".into(),
                title: "新标题".into(),
            },
            reason: None,
            refs: vec![],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateTitle");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"page.head.updateTitle\""));
    }

    #[test]
    fn document_save_command_maps_to_documents_update_content() {
        let command = CommandEnvelope {
            name: "documents.save".into(),
            command_id: "cmd_save_1".into(),
            idempotency_key: Some("idem_save".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: SavePageContent {
                page_id: "page_1".into(),
                workspace_id: Some("ws_1".into()),
                revision: Some(42),
                content_json: "{\"type\":\"doc\"}".into(),
                conflict_detection_key: Some("rev:42".into()),
            },
            reason: Some("保存正文".into()),
            refs: vec!["checklist:c3".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateContent");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"documents.save\""));
    }

    #[test]
    fn page_body_save_command_maps_to_documents_update_content() {
        let command = CommandEnvelope {
            name: "page.body.save".into(),
            command_id: "cmd_page_save_1".into(),
            idempotency_key: Some("idem_page_save".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: SavePageContent {
                page_id: "page_1".into(),
                workspace_id: Some("ws_1".into()),
                revision: Some(42),
                content_json: "{\"type\":\"doc\"}".into(),
                conflict_detection_key: Some("rev:42".into()),
            },
            reason: Some("保存正文".into()),
            refs: vec!["checklist:c3".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateContent");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"page.body.save\""));
    }

    #[test]
    fn document_embed_command_maps_to_documents_update_content() {
        let command = CommandEnvelope {
            name: "documents.embed".into(),
            command_id: "cmd_embed_1".into(),
            idempotency_key: Some("idem_embed".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_2".into()),
                block_id: None,
            }),
            payload: SavePageContent {
                page_id: "page_2".into(),
                workspace_id: Some("ws_1".into()),
                revision: Some(7),
                content_json: "{\"blocks\":[{\"id\":\"block_1\",\"type\":\"pageReference\"}]}"
                    .into(),
                conflict_detection_key: Some("rev:7".into()),
            },
            reason: Some("嵌入页面".into()),
            refs: vec!["checklist:p1-3".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateContent");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"documents.embed\""));
    }

    #[test]
    fn page_lifecycle_commands_map_to_document_mutations() {
        let base_actor = ActorPayload {
            actor_type: "human".into(),
            actor_id: "user_1".into(),
            session_id: Some("session_1".into()),
        };
        let base_source = SourcePayload {
            channel: "next-route".into(),
            client: "wolai-frontend".into(),
        };

        let create_request = build_write_request(
            &demo_context(),
            &CommandEnvelope {
                name: "documents.create".into(),
                command_id: "cmd_create_1".into(),
                idempotency_key: Some("idem_create".into()),
                actor: base_actor.clone(),
                source: base_source.clone(),
                target: Some(TargetRef {
                    workspace_id: None,
                    page_id: Some("page_1".into()),
                    block_id: None,
                }),
                payload: CreateDocumentPage {
                    page_id: "page_1".into(),
                    parent_page_id: Some("parent_1".into()),
                    title: "无标题".into(),
                    workspace_seed_id: "ws_seed_1".into(),
                },
                reason: Some("创建页面".into()),
                refs: vec![],
                dry_run: false,
                validate_only: false,
            },
        )
        .expect("create request should build");
        assert_eq!(
            create_request.function_name,
            "documents:createWithParentReference"
        );

        let move_request = build_write_request(
            &demo_context(),
            &CommandEnvelope {
                name: "documents.move".into(),
                command_id: "cmd_move_1".into(),
                idempotency_key: Some("idem_move".into()),
                actor: base_actor.clone(),
                source: base_source.clone(),
                target: Some(TargetRef {
                    workspace_id: None,
                    page_id: Some("page_1".into()),
                    block_id: None,
                }),
                payload: MoveDocumentPage {
                    page_id: "page_1".into(),
                    parent_page_id: Some("parent_2".into()),
                    sort_order: 3,
                },
                reason: Some("移动页面".into()),
                refs: vec![],
                dry_run: false,
                validate_only: false,
            },
        )
        .expect("move request should build");
        assert_eq!(move_request.function_name, "documents:move");

        let delete_request = build_write_request(
            &demo_context(),
            &CommandEnvelope {
                name: "documents.delete".into(),
                command_id: "cmd_delete_1".into(),
                idempotency_key: Some("idem_delete".into()),
                actor: base_actor.clone(),
                source: base_source.clone(),
                target: Some(TargetRef {
                    workspace_id: None,
                    page_id: Some("page_1".into()),
                    block_id: None,
                }),
                payload: DeleteDocumentPage {
                    page_id: "page_1".into(),
                },
                reason: Some("删除页面".into()),
                refs: vec![],
                dry_run: false,
                validate_only: false,
            },
        )
        .expect("delete request should build");
        assert_eq!(delete_request.function_name, "documents:softDelete");

        let restore_request = build_write_request(
            &demo_context(),
            &CommandEnvelope {
                name: "documents.restore".into(),
                command_id: "cmd_restore_1".into(),
                idempotency_key: Some("idem_restore".into()),
                actor: base_actor.clone(),
                source: base_source.clone(),
                target: Some(TargetRef {
                    workspace_id: None,
                    page_id: Some("page_1".into()),
                    block_id: None,
                }),
                payload: RestoreDocumentPage {
                    page_id: "page_1".into(),
                },
                reason: Some("恢复页面".into()),
                refs: vec![],
                dry_run: false,
                validate_only: false,
            },
        )
        .expect("restore request should build");
        assert_eq!(restore_request.function_name, "documents:restore");

        let duplicate_request = build_write_request(
            &demo_context(),
            &CommandEnvelope {
                name: "documents.duplicate".into(),
                command_id: "cmd_duplicate_1".into(),
                idempotency_key: Some("idem_duplicate".into()),
                actor: base_actor.clone(),
                source: base_source.clone(),
                target: Some(TargetRef {
                    workspace_id: None,
                    page_id: Some("page_copy_1".into()),
                    block_id: None,
                }),
                payload: DuplicateDocumentPage {
                    source_page_id: "page_1".into(),
                    new_page_id: "page_copy_1".into(),
                    title: Some("无标题 副本".into()),
                },
                reason: Some("复制页面".into()),
                refs: vec![],
                dry_run: false,
                validate_only: false,
            },
        )
        .expect("duplicate request should build");
        assert_eq!(
            duplicate_request.function_name,
            "documents:duplicateWithMindmaps"
        );

        let copy_tree_request = build_write_request(
            &demo_context(),
            &CommandEnvelope {
                name: "documents.copy_tree".into(),
                command_id: "cmd_copy_tree_1".into(),
                idempotency_key: Some("idem_copy_tree".into()),
                actor: base_actor,
                source: base_source,
                target: Some(TargetRef {
                    workspace_id: None,
                    page_id: Some("target_parent_1".into()),
                    block_id: None,
                }),
                payload: CopyTreeDocumentPages {
                    items_json: "[{\"documentId\":\"page_1\",\"recursive\":true}]".into(),
                    target_parent_page_id: Some("target_parent_1".into()),
                },
                reason: Some("复制页面树".into()),
                refs: vec![],
                dry_run: false,
                validate_only: false,
            },
        )
        .expect("copy tree request should build");
        assert_eq!(copy_tree_request.function_name, "documents:copyTree");
    }

    #[test]
    fn block_patch_command_maps_to_documents_update_content() {
        let command = CommandEnvelope {
            name: "blocks.patch".into(),
            command_id: "cmd_patch_1".into(),
            idempotency_key: Some("idem_patch".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: Some("block_1".into()),
            }),
            payload: PatchPageBlock {
                page_id: "page_1".into(),
                block_id: "block_1".into(),
                workspace_id: Some("ws_1".into()),
                revision: Some(7),
                block_snapshot_json: "{\"id\":\"block_1\",\"type\":\"paragraph\"}".into(),
                conflict_detection_key: Some("page:1:block:1".into()),
            },
            reason: Some("替换块快照".into()),
            refs: vec!["checklist:c3".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateContent");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"blocks.patch\""));
    }

    #[test]
    fn blocks_get_query_maps_to_blocks_get_by_id() {
        let query = QueryEnvelope {
            name: "blocks.get".into(),
            payload: GetBlock {
                block_id: "block_1".into(),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "blocks:getById");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"blocks.get\""));
    }

    #[test]
    fn document_stats_command_maps_to_documents_update_stats() {
        let command = CommandEnvelope {
            name: "documents.stats.update".into(),
            command_id: "cmd_stats_1".into(),
            idempotency_key: Some("idem_stats".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: UpdatePageStats {
                page_id: "page_1".into(),
                word_count: 10,
                character_count: 20,
                block_count: 3,
                todo_total: 4,
                todo_done: 1,
            },
            reason: None,
            refs: vec![],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateStats");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"documents.stats.update\""));
    }

    #[test]
    fn document_options_command_maps_to_documents_update_options() {
        let command = CommandEnvelope {
            name: "documents.options.update".into(),
            command_id: "cmd_options_1".into(),
            idempotency_key: Some("idem_options".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: UpdatePageOptions {
                page_id: "page_1".into(),
                wide_layout: None,
                small_text: None,
                show_heading_numbers: None,
                show_toc: Some(true),
                show_structure: None,
                protect_editing: None,
                show_word_count: None,
                collapse_backlinks: None,
                page_font: None,
                layout_density: Some("compact".into()),
                hide_child_pages: None,
                show_block_ref_count: None,
                embed_default_block_id: None,
            },
            reason: None,
            refs: vec![],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateOptions");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"documents.options.update\""));
    }

    #[test]
    fn page_layout_update_options_command_maps_to_documents_update_options() {
        let command = CommandEnvelope {
            name: "page.layout.updateOptions".into(),
            command_id: "cmd_page_options_1".into(),
            idempotency_key: Some("idem_page_options".into()),
            actor: ActorPayload {
                actor_type: "human".into(),
                actor_id: "user_1".into(),
                session_id: Some("session_1".into()),
            },
            source: SourcePayload {
                channel: "next-route".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: UpdatePageOptions {
                page_id: "page_1".into(),
                wide_layout: None,
                small_text: None,
                show_heading_numbers: None,
                show_toc: Some(true),
                show_structure: None,
                protect_editing: None,
                show_word_count: None,
                collapse_backlinks: None,
                page_font: None,
                layout_density: Some("compact".into()),
                hide_child_pages: None,
                show_block_ref_count: None,
                embed_default_block_id: None,
            },
            reason: None,
            refs: vec![],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "documents:updateOptions");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"page.layout.updateOptions\""));
    }

    #[test]
    fn media_asset_writeback_command_maps_to_replace_storage_from_upload() {
        let command = CommandEnvelope {
            name: "media.assets.replace_storage".into(),
            command_id: "cmd_asset_1".into(),
            idempotency_key: Some("idem_asset".into()),
            actor: ActorPayload {
                actor_type: "service".into(),
                actor_id: "onlyoffice-callback".into(),
                session_id: Some("onlyoffice".into()),
            },
            source: SourcePayload {
                channel: "onlyoffice-callback".into(),
                client: "wolai-frontend".into(),
            },
            target: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: None,
            }),
            payload: ReplaceMediaAssetStorage {
                asset_id: "asset_1".into(),
                storage_id: "storage_1".into(),
            },
            reason: Some("ONLYOFFICE 回调写回附件".into()),
            refs: vec!["checklist:d".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(
            request.function_name,
            "mediaAssets:replaceStorageFromUpload"
        );
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"media.assets.replace_storage\""));
    }

    #[test]
    fn document_meta_query_maps_to_documents_get_meta() {
        let query = QueryEnvelope {
            name: "documents.meta.get".into(),
            payload: GetPageMeta {
                page_id: "page_1".into(),
                workspace_id: Some("ws_1".into()),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "documents:getMeta");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"documents.meta.get\""));
    }

    #[test]
    fn document_content_query_maps_to_documents_get_content() {
        let query = QueryEnvelope {
            name: "documents.content.get".into(),
            payload: GetPageContent {
                page_id: "page_1".into(),
                workspace_id: Some("ws_1".into()),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "documents:getContent");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"documents.content.get\""));
    }

    #[test]
    fn mindmap_get_query_maps_to_mindmaps_get() {
        let query = QueryEnvelope {
            name: "mindmaps.get".into(),
            payload: GetMindmap {
                document_id: "page_1".into(),
                mindmap_id: "mind_1".into(),
                workspace_id: Some("ws_1".into()),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "mindmaps:get");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"mindmaps.get\""));
    }

    #[test]
    fn sidebar_dataset_query_maps_to_sidebar_dataset_list() {
        let query = QueryEnvelope {
            name: "sidebar.dataset.list".into(),
            payload: ListSidebarDataset {
                workspace_id: "ws_1".into(),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "sidebar:datasetList");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"sidebar.dataset.list\""));
    }

    #[test]
    fn search_documents_query_maps_to_search_documents() {
        let query = QueryEnvelope {
            name: "search.documents".into(),
            payload: SearchDocuments {
                query: "rust".into(),
                workspace_id: "ws_1".into(),
                page_id: Some("page_1".into()),
                pagination: core_protocol::query::Pagination {
                    limit: 20,
                    cursor: None,
                },
                title_only: false,
                exact: false,
                include_ocr: true,
                time_range: "any".into(),
                time_field: "updated".into(),
                custom_range_from: None,
                custom_range_to: None,
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "search:documents");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"search.documents\""));
    }

    #[test]
    fn search_recent_query_maps_to_search_recent() {
        let query = QueryEnvelope {
            name: "search.recent".into(),
            payload: SearchRecent {
                workspace_id: "ws_1".into(),
                pagination: core_protocol::query::Pagination {
                    limit: 10,
                    cursor: None,
                },
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "search:recent");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"search.recent\""));
    }

    #[test]
    fn bridge_request_query_maps_to_bridge_logs_request() {
        let query = QueryEnvelope {
            name: "bridge.request.get".into(),
            payload: GetBridgeRequest {
                workspace_id: "ws_1".into(),
                request_id: "req_1".into(),
                command_id: Some("cmd_1".into()),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "bridgeLogs:listByRequest");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"bridge.request.get\""));
    }

    #[test]
    fn bridge_trace_query_maps_to_bridge_logs_trace() {
        let query = QueryEnvelope {
            name: "bridge.trace.get".into(),
            payload: GetBridgeTrace {
                workspace_id: "ws_1".into(),
                trace_id: "trace_1".into(),
                command_id: None,
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "bridgeLogs:listByTrace");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"bridge.trace.get\""));
    }

    #[test]
    fn bridge_command_query_maps_to_bridge_logs_command() {
        let query = QueryEnvelope {
            name: "bridge.command.get".into(),
            payload: GetBridgeCommand {
                workspace_id: "ws_1".into(),
                command_id: "cmd_1".into(),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "bridgeLogs:listByCommand");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"bridge.command.get\""));
    }

    #[test]
    fn bridge_workspace_overview_query_maps_to_bridge_logs_workspace_overview() {
        let query = QueryEnvelope {
            name: "bridge.workspace.overview".into(),
            payload: ListBridgeWorkspaceOverview {
                workspace_id: "ws_1".into(),
                pagination: core_protocol::query::Pagination {
                    limit: 20,
                    cursor: Some("cursor_1".into()),
                },
                command_status: Some("failed".into()),
                event_status: Some("failed".into()),
                target_page_id: Some("page_1".into()),
                target_block_id: None,
                aggregate_type: Some("page".into()),
                aggregate_id: Some("page_1".into()),
            },
        };

        let request =
            build_query_request(&demo_context(), &query).expect("query request should build");
        assert_eq!(request.function_name, "bridgeLogs:listWorkspaceOverview");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request
            .payload_json
            .contains("\"name\":\"bridge.workspace.overview\""));
    }

    #[test]
    fn mindmap_put_command_maps_to_mindmaps_put() {
        let command = CommandEnvelope {
            name: "mindmaps.put".into(),
            command_id: "cmd_mindmap_put_1".into(),
            idempotency_key: Some("idem_mindmap_put".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: Some(TargetRef {
                workspace_id: Some("ws_1".into()),
                page_id: Some("page_1".into()),
                block_id: Some("mind_1".into()),
            }),
            payload: PutMindmap {
                document_id: "page_1".into(),
                mindmap_id: "mind_1".into(),
                data_json: r#"{"data":{"text":"中心主题"},"children":[]}"#.into(),
                create_only: false,
            },
            reason: Some("保存导图".into()),
            refs: vec!["task-032".into()],
            dry_run: false,
            validate_only: false,
        };

        let request =
            build_write_request(&demo_context(), &command).expect("write request should build");
        assert_eq!(request.function_name, "mindmaps:put");
        assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
        assert!(request.payload_json.contains("\"name\":\"mindmaps.put\""));
    }
}
