use crate::app::AppConfig;
use crate::context::RequestContext;
use crate::error::WebError;
use crate::transport::convex::execute_convex_command_plan;
use bridge_runtime::{
    execute_runtime_input, RuntimeActorWire, RuntimeBridgeContextWire, RuntimeCommandEnvelopeWire,
    RuntimeCommandExecutionPlan, RuntimeExecutionPlan, RuntimeInput, RuntimeSourceWire,
    RuntimeTargetWire,
};
use serde_json::Value;

pub fn runtime_context(
    context: &RequestContext,
    effective_workspace_id: Option<&str>,
) -> RuntimeBridgeContextWire {
    RuntimeBridgeContextWire {
        deployment_id: context.workspace.deployment_id.clone(),
        project_id: context.workspace.project_id.clone(),
        workspace_id: effective_workspace_id
            .map(ToOwned::to_owned)
            .or_else(|| context.workspace.workspace_id.clone()),
        request_id: context.trace.request_id.clone(),
        trace_id: context.trace.trace_id.clone(),
        actor: RuntimeActorWire {
            actor_type: context.auth.actor_type.clone(),
            actor_id: context.auth.actor_id.clone(),
            session_id: context.auth.session_id.clone(),
        },
        source: RuntimeSourceWire {
            channel: context.source.channel.clone(),
            client: context.source.client.clone(),
        },
        tenant_id: context.workspace.tenant_id.clone(),
        auth_token: context.auth.authorization.clone(),
        idempotency_key: context.source.idempotency_key.clone(),
        validate_only: false,
        dry_run: false,
    }
}

pub fn build_runtime_command_plan(
    context: &RequestContext,
    effective_workspace_id: Option<&str>,
    command: RuntimeCommandEnvelopeWire,
) -> Result<RuntimeCommandExecutionPlan, WebError> {
    let runtime_input = RuntimeInput::Command {
        context: runtime_context(context, effective_workspace_id),
        command,
    };
    let RuntimeExecutionPlan::Command(plan) = execute_runtime_input(runtime_input)
        .map_err(|error| WebError::bad_request(error.message).with_context(context))?
    else {
        return Err(WebError::internal("runtime command 未返回 command plan").with_context(context));
    };

    Ok(plan)
}

pub async fn execute_runtime_command_via_convex(
    config: &AppConfig,
    context: &RequestContext,
    effective_workspace_id: Option<&str>,
    command: RuntimeCommandEnvelopeWire,
) -> Result<Value, WebError> {
    let plan = build_runtime_command_plan(context, effective_workspace_id, command)?;
    execute_convex_command_plan(config, context, &plan).await
}

pub fn build_tree_target(
    workspace_id: &str,
    page_id: Option<&str>,
    block_id: Option<&str>,
) -> RuntimeTargetWire {
    RuntimeTargetWire {
        workspace_id: Some(workspace_id.to_string()),
        page_id: page_id.map(ToOwned::to_owned),
        block_id: block_id.map(ToOwned::to_owned),
    }
}

pub fn ensure_non_empty(
    value: &str,
    field: &'static str,
    context: &RequestContext,
) -> Result<String, WebError> {
    let trimmed = value.trim();
    if trimmed.is_empty() {
        return Err(WebError::bad_request_code(
            "tree_command_validation",
            format!("{field} 不能为空"),
        )
        .with_context(context)
        .with_header("x-error-phase", "tree_command_validate"));
    }
    Ok(trimmed.to_string())
}

pub fn read_optional_non_empty(value: Option<String>) -> Option<String> {
    value
        .map(|item| item.trim().to_string())
        .filter(|item| !item.is_empty())
}

pub fn ensure_sort_order(sort_order: i64, context: &RequestContext) -> Result<i64, WebError> {
    if sort_order < 0 {
        return Err(
            WebError::bad_request_code("tree_command_validation", "sortOrder 不能小于 0")
                .with_context(context)
                .with_header("x-error-phase", "tree_command_validate"),
        );
    }
    Ok(sort_order)
}
