// @generated by flare-im-core-sdk-xtask
// Source: bindings/contract/direct_invoke.json

use flare_im_core_sdk::serde_json::{self, Value};

use crate::dispatch_support;
use crate::{BindingResponse, InvokeSession};
use flare_im_core_sdk::Result;
use flare_im_core_sdk::SdkState;

/// Routes handled outside JSON dispatch match tables.
pub const DIRECT_INVOKE_ROUTES: &[&str] = &[
    "sdk.init",
    "sdk.uninit",
    "sync.conversation_summaries",
    "sync.conversation_summaries_with_versions",
    "sync.bootstrap_startup_home",
    "sync.conversation_history_backfill",
    "sync.conversation",
    "sync.messages",
    "user.upsert_profiles",
    "presence.get",
    "presence.batch_get",
    "presence.subscribe",
    "connection.get_state",
    "connection.disconnect",
    "sdk.is_connected",
    "sdk.session_active",
    "sdk.current_user_id",
    "sdk.generate_core_token",
    "sdk.update_access_token",
    "sdk.set_heartbeat_app_state",
    "sdk.set_heartbeat_nat_timeout",
    "sdk.heartbeat_effective_interval",
    "connection.notify_network_change",
    "message_builder.list_catalog",
    "message.create_text",
    "rich_doc_v2.normalize_from_markdown",
    "rich_doc_v2.normalize_from_html",
    "rich_doc_v2.normalize_from_doc_json",
    "diagnostics.sdk_version",
    "diagnostics.ffi_contract_version",
    "diagnostics.data_root",
    "diagnostics.runtime_health",
    #[cfg(not(target_arch = "wasm32"))]
    "media.cancel_user_file_download",
    #[cfg(not(target_arch = "wasm32"))]
    "media.download_file_to_downloads",
];

pub fn is_direct_invoke_route(route: &str) -> bool {
    match route {
        "sdk.init" => true,
        "sdk.uninit" => true,
        "sync.conversation_summaries" => true,
        "sync.conversation_summaries_with_versions" => true,
        "sync.bootstrap_startup_home" => true,
        "sync.conversation_history_backfill" => true,
        "sync.conversation" => true,
        "sync.messages" => true,
        "user.upsert_profiles" => true,
        "presence.get" => true,
        "presence.batch_get" => true,
        "presence.subscribe" => true,
        "connection.get_state" => true,
        "connection.disconnect" => true,
        "sdk.is_connected" => true,
        "sdk.session_active" => true,
        "sdk.current_user_id" => true,
        "sdk.generate_core_token" => true,
        "sdk.update_access_token" => true,
        "sdk.set_heartbeat_app_state" => true,
        "sdk.set_heartbeat_nat_timeout" => true,
        "sdk.heartbeat_effective_interval" => true,
        "connection.notify_network_change" => true,
        "message_builder.list_catalog" => true,
        "message.create_text" => true,
        "rich_doc_v2.normalize_from_markdown" => true,
        "rich_doc_v2.normalize_from_html" => true,
        "rich_doc_v2.normalize_from_doc_json" => true,
        "diagnostics.sdk_version" => true,
        "diagnostics.ffi_contract_version" => true,
        "diagnostics.data_root" => true,
        "diagnostics.runtime_health" => true,
        #[cfg(not(target_arch = "wasm32"))]
        "media.cancel_user_file_download" => true,
        #[cfg(not(target_arch = "wasm32"))]
        "media.download_file_to_downloads" => true,
        _ => false,
    }
}

fn sdk_state_json(state: SdkState) -> (&'static str, i32) {
    use SdkState as S;
    match state {
        S::Disconnected => ("disconnected", 0),
        S::Connecting => ("connecting", 1),
        S::Connected => ("connected", 2),
        S::Ready => ("ready", 3),
        S::Reconnecting => ("reconnecting", 4),
    }
}

#[derive(flare_im_core_sdk::serde::Deserialize)]
#[serde(crate = "flare_im_core_sdk::serde", rename_all = "camelCase")]
struct SyncMessagesDirectRequest {
    conversation_id: String,
    last_seq: u64,
    #[serde(default)]
    limit: Option<i32>,
}

pub async fn dispatch_direct(
    session: &impl InvokeSession,
    route: &str,
    request: &Value,
) -> Result<BindingResponse> {
    match route {
        "sdk.init" => {
            let environment = dispatch_support::optional_string(request, "environment");
            let sdk_config = dispatch_support::optional_value::<
                flare_im_core_sdk::client::lifecycle::SdkConfigOverlay,
            >(request, "sdkConfig")?;
            session.client().init(environment, sdk_config).await?;
            Ok(BindingResponse::unit())
        }
        "sdk.uninit" => {
            session.after_disconnect().await;
            session.client().uninit().await?;
            Ok(BindingResponse::unit())
        }
        "sync.conversation_summaries" => {
            let client = session.client();
            client.sync_conversation_summaries_silent().await?;
            Ok(BindingResponse::unit())
        }
        "sync.conversation_summaries_with_versions" => {
            let client = session.client();
            let request = dispatch_support::from_value::<
                flare_im_core_sdk::model::SyncConversationSummariesRequest,
            >(request.clone(), "sync conversation summaries request")?;
            let response = client
                .sync_conversation_summaries_with_versions(request)
                .await?;
            dispatch_support::json(response)
        }
        "sync.bootstrap_startup_home" => {
            let client = session.client();
            let request = dispatch_support::from_value::<
                flare_im_core_sdk::model::StartupHomeSyncRequest,
            >(request.clone(), "startup home sync request")?;
            let response = client.bootstrap_startup_home(request).await?;
            dispatch_support::json(response)
        }
        "sync.conversation_history_backfill" => {
            let client = session.client();
            let conversation_id = dispatch_support::json_string(request, "conversationId")?;
            let limit = dispatch_support::optional_i32(request, "limit")?.unwrap_or(500);
            let max_pages = dispatch_support::optional_u32(request, "maxPages")?.unwrap_or(128);
            let response = client
                .backfill_conversation_history(&conversation_id, limit, max_pages)
                .await?;
            dispatch_support::json(response)
        }
        "sync.conversation" => {
            let client = session.client();
            let conversation_id = dispatch_support::json_string(request, "conversationId")?;
            client.sync_conversation(&conversation_id).await?;
            Ok(BindingResponse::unit())
        }
        "sync.messages" => {
            let client = session.client();
            let conversation_id = dispatch_support::json_string(request, "conversationId")?;
            let last_seq = dispatch_support::json_u64(request, "lastSeq")?;
            let limit = dispatch_support::optional_i32(request, "limit")?.unwrap_or(50);
            client
                .sync_messages(&conversation_id, last_seq, limit)
                .await?;
            Ok(BindingResponse::unit())
        }
        "user.upsert_profiles" => {
            let client = session.client();
            let profiles = dispatch_support::optional_value::<
                Vec<flare_im_core_sdk::spi::UserProfile>,
            >(request, "profiles")?
            .unwrap_or_default();
            client.upsert_user_profiles(profiles).await?;
            Ok(BindingResponse::unit())
        }
        "presence.get" => {
            let client = session.client();
            let user_id = dispatch_support::json_string(request, "userId")?;
            let dto = client.get_user_presence(&user_id).await?;
            dispatch_support::json(dto)
        }
        "presence.batch_get" => {
            let client = session.client();
            let user_ids = dispatch_support::json_vec_string(request, "userIds")?;
            let items = client.batch_get_user_presence(&user_ids).await?;
            dispatch_support::json(items)
        }
        "presence.subscribe" => {
            let client = session.client();
            let user_ids = dispatch_support::json_vec_string(request, "userIds")?;
            client.subscribe_user_presence(user_ids).await?;
            Ok(BindingResponse::unit())
        }
        "connection.get_state" => {
            let client = session.client();
            let state = client.state();
            let (name, _code) = sdk_state_json(state);
            dispatch_support::json(serde_json::json!(name))
        }
        "connection.disconnect" => {
            let client = session.client();
            session.after_disconnect().await;
            client.disconnect().await?;
            Ok(BindingResponse::unit())
        }
        "sdk.is_connected" => {
            let client = session.client();
            let connected = client.is_connected().await;
            dispatch_support::json(serde_json::json!(connected))
        }
        "sdk.session_active" => {
            let client = session.client();
            let active = client.session_active_sync();
            dispatch_support::json(serde_json::json!(active))
        }
        "sdk.current_user_id" => {
            let client = session.client();
            let user_id = client.current_user_id().await;
            dispatch_support::json(serde_json::json!({ "userId": user_id }))
        }
        "sdk.generate_core_token" => {
            let secret = dispatch_support::json_string(request, "secret")?;
            let issuer = dispatch_support::json_string(request, "issuer")?;
            let user_id = dispatch_support::json_string(request, "userId")?;
            let ttl_secs = dispatch_support::json_u64(request, "ttlSecs")?;
            let device_id = dispatch_support::optional_string(request, "deviceId");
            let tenant_id = dispatch_support::optional_string(request, "tenantId");
            let token = flare_im_core_sdk::client::IMClient::generate_core_token(
                flare_im_core_sdk::client::CoreTokenConfig {
                    secret,
                    issuer,
                    user_id,
                    ttl_secs,
                    device_id,
                    tenant_id,
                },
            )?;
            dispatch_support::json(serde_json::json!({ "token": token }))
        }
        "sdk.update_access_token" => {
            let client = session.client();
            let access_token = dispatch_support::json_string(request, "accessToken")?;
            let tenant_id = dispatch_support::optional_string(request, "tenantId");
            client
                .update_access_token(access_token, tenant_id.as_deref())
                .await?;
            Ok(BindingResponse::unit())
        }
        "sdk.set_heartbeat_app_state" => {
            let client = session.client();
            let state = dispatch_support::heartbeat_app_state(request, "appState")?;
            client.set_heartbeat_app_state(state).await?;
            Ok(BindingResponse::unit())
        }
        "sdk.set_heartbeat_nat_timeout" => {
            let client = session.client();
            let nat_timeout_secs = dispatch_support::optional_u32(request, "natTimeoutSecs")?;
            client
                .set_heartbeat_nat_timeout(
                    nat_timeout_secs.map(|secs| std::time::Duration::from_secs(secs as u64)),
                )
                .await?;
            Ok(BindingResponse::unit())
        }
        "sdk.heartbeat_effective_interval" => {
            let client = session.client();
            let interval = client.heartbeat_effective_interval().await?;
            let response = match interval {
                Some(duration) => serde_json::json!({
                    "connected": true,
                    "intervalMs": duration.as_millis() as u64,
                    "intervalSecs": duration.as_secs(),
                }),
                None => serde_json::json!({
                    "connected": false,
                    "intervalMs": null,
                    "intervalSecs": null,
                }),
            };
            dispatch_support::json(response)
        }
        "connection.notify_network_change" => {
            let client = session.client();
            let event = flare_im_core_sdk::client::NetworkChangeEvent {
                available: dispatch_support::optional_bool(request, "available")?.unwrap_or(true),
                interface: dispatch_support::optional_string(request, "interface"),
                expensive: dispatch_support::optional_bool(request, "expensive")?,
                metered: dispatch_support::optional_bool(request, "metered")?,
                reason: dispatch_support::optional_string(request, "reason"),
            };
            let reconnected = client.notify_network_change(event).await?;
            dispatch_support::json(serde_json::json!({ "reconnected": reconnected }))
        }
        "message_builder.list_catalog" => dispatch_support::json(
            serde_json::json!({ "entries": crate::operation::message_build_catalog() }),
        ),
        "message.create_text" => {
            let conversation_id = dispatch_support::json_string(request, "conversationId")?;
            let text = dispatch_support::json_string(request, "text")?;
            let mention_users =
                dispatch_support::optional_value::<Vec<String>>(request, "mentionUsers")?
                    .unwrap_or_default();
            let mention_all =
                dispatch_support::optional_bool(request, "mentionAll")?.unwrap_or(false);
            let api = session.message_build_api().await?;
            let message = api
                .create_text(&conversation_id, &text, mention_all, &mention_users)
                .await?;
            dispatch_support::json(message)
        }
        "rich_doc_v2.normalize_from_markdown" => {
            let markdown = dispatch_support::json_string(request, "markdown")?;
            let normalized =
                dispatch_support::run_cpu_bound("rich_doc_v2.normalize_from_markdown", move || {
                    flare_im_core_sdk::content::rich_doc_v2::normalize_from_markdown(&markdown)
                        .map_err(|error| crate::binding_invalid_parameter(error.to_string()))
                })
                .await?;
            let source_payload = normalized
                .source_payload
                .as_ref()
                .map(|(key, value)| serde_json::json!({ key: value }));
            dispatch_support::json(serde_json::json!({
                "docJson": normalized.doc_json,
                "contentSchema": normalized.content_schema,
                "version": normalized.version,
                "plainText": normalized.plain_text,
                "searchText": normalized.search_text,
                "renderHints": normalized.render_hints,
                "inputFormat": normalized.input_format,
                "sourcePayload": source_payload,
            }))
        }
        "rich_doc_v2.normalize_from_html" => {
            let html = dispatch_support::json_string(request, "html")?;
            let normalized =
                dispatch_support::run_cpu_bound("rich_doc_v2.normalize_from_html", move || {
                    flare_im_core_sdk::content::rich_doc_v2::normalize_from_html(&html)
                        .map_err(|error| crate::binding_invalid_parameter(error.to_string()))
                })
                .await?;
            let source_payload = normalized
                .source_payload
                .as_ref()
                .map(|(key, value)| serde_json::json!({ key: value }));
            dispatch_support::json(serde_json::json!({
                "docJson": normalized.doc_json,
                "contentSchema": normalized.content_schema,
                "version": normalized.version,
                "plainText": normalized.plain_text,
                "searchText": normalized.search_text,
                "renderHints": normalized.render_hints,
                "inputFormat": normalized.input_format,
                "sourcePayload": source_payload,
            }))
        }
        "rich_doc_v2.normalize_from_doc_json" => {
            let doc_json = dispatch_support::json_string(request, "docJson")?;
            let normalized =
                dispatch_support::run_cpu_bound("rich_doc_v2.normalize_from_doc_json", move || {
                    flare_im_core_sdk::content::rich_doc_v2::normalize_from_doc_json(&doc_json)
                        .map_err(|error| crate::binding_invalid_parameter(error.to_string()))
                })
                .await?;
            let source_payload = normalized
                .source_payload
                .as_ref()
                .map(|(key, value)| serde_json::json!({ key: value }));
            dispatch_support::json(serde_json::json!({
                "docJson": normalized.doc_json,
                "contentSchema": normalized.content_schema,
                "version": normalized.version,
                "plainText": normalized.plain_text,
                "searchText": normalized.search_text,
                "renderHints": normalized.render_hints,
                "inputFormat": normalized.input_format,
                "sourcePayload": source_payload,
            }))
        }
        "diagnostics.sdk_version" => {
            dispatch_support::json(serde_json::json!({ "version": env!("CARGO_PKG_VERSION") }))
        }
        "diagnostics.ffi_contract_version" => dispatch_support::json(
            serde_json::json!({ "version": crate::contract::BINDING_CONTRACT_VERSION }),
        ),
        "diagnostics.data_root" => {
            let client = session.client();
            let data_root = client.data_root().await;
            dispatch_support::json(serde_json::json!({
                "dataRoot": data_root.as_ref().map(|p| p.display().to_string())
            }))
        }
        "diagnostics.runtime_health" => {
            let client = session.client();
            let snapshot = client.runtime_health_snapshot().await;
            let metrics_json =
                serde_json::to_string(&snapshot.metrics).unwrap_or_else(|_| "{}".to_string());
            let (state, state_code) = sdk_state_json(snapshot.state);
            dispatch_support::json(serde_json::json!({
                "metricsEnabled": snapshot.metrics_enabled,
                "state": state,
                "stateCode": state_code,
                "sessionGeneration": snapshot.session_generation,
                "rawSubscriberDroppedTotal": snapshot.raw_subscriber_dropped_total,
                "metricsJson": metrics_json
            }))
        }
        #[cfg(not(target_arch = "wasm32"))]
        "media.cancel_user_file_download" => {
            let api = session.media_api().await?;
            let download_key = dispatch_support::json_string(request, "downloadKey")?;
            let cancelled = api.cancel_user_file_download(&download_key);
            dispatch_support::json(serde_json::json!({ "cancelled": cancelled }))
        }
        #[cfg(not(target_arch = "wasm32"))]
        "media.download_file_to_downloads" => {
            let api = session.media_api().await?;
            let download_key = dispatch_support::json_string(request, "downloadKey")?;
            let display_file_name = dispatch_support::json_string(request, "displayFileName")?;
            let source_path = dispatch_support::optional_string(request, "sourcePath");
            let source_http_url = dispatch_support::optional_string(request, "sourceHttpUrl");
            let remote_file_id = dispatch_support::optional_string(request, "remoteFileId");
            let expires_in = dispatch_support::optional_i32(request, "expiresIn")?.unwrap_or(3600);
            let path = api
                .download_file_to_user_downloads_folder(
                    flare_im_core_sdk::prelude::UserFileDownloadRequest {
                        download_key,
                        display_file_name,
                        source_path,
                        source_http_url,
                        remote_file_id,
                        expires_in,
                        on_progress: None,
                    },
                )
                .await?;
            dispatch_support::json(serde_json::json!({ "path": path }))
        }
        _ => Err(crate::binding_operation_not_supported(route)),
    }
}

pub async fn dispatch_direct_json(
    session: &impl InvokeSession,
    route: &str,
    request_json: &str,
) -> Result<BindingResponse> {
    match route {
        "sync.messages" => {
            let client = session.client();
            let request = dispatch_support::from_json_str::<SyncMessagesDirectRequest>(
                request_json,
                "sync messages request",
            )?;
            client
                .sync_messages(
                    &request.conversation_id,
                    request.last_seq,
                    request.limit.unwrap_or(50),
                )
                .await?;
            Ok(BindingResponse::unit())
        }
        "sync.conversation_summaries_with_versions" => {
            let client = session.client();
            let request = dispatch_support::from_json_str::<
                flare_im_core_sdk::model::SyncConversationSummariesRequest,
            >(request_json, "sync conversation summaries request")?;
            let response = client
                .sync_conversation_summaries_with_versions(request)
                .await?;
            dispatch_support::json(response)
        }
        _ => {
            let request = dispatch_support::dispatch_params_from_json(request_json)?;
            dispatch_direct(session, route, &request).await
        }
    }
}
