///|
/// ═══ 功能组:context(Agent 状态)═══
/// Context/SdkMessage/SdkTool 构建与 context_to_lux_request。

///|
/// Context — 对话上下文构建器
///
/// 面向 L1/L2 开发者,隐藏 IR 类型细节。
/// 内部将用户输入转换为 LucentConversationItem。

///|
/// SdkToolCall — SDK 层的 assistant 工具调用回合
///
/// Agent 循环第二轮必需:模型发出 tool_call 后,transcript 中必须先有
/// 对应的 assistant tool_use 回合,provider(Anthropic/OpenAI 均硬校验)
/// 才接受紧随其后的 tool_result。
pub struct SdkToolCall {
  id : String
  name : String
  arguments_json : String
}

///|
pub fn SdkToolCall::new(
  id : String,
  name : String,
  arguments_json : String,
) -> SdkToolCall {
  { id, name, arguments_json, }
}

///|
/// SdkMessage — SDK 层的消息表示
pub struct SdkMessage {
  role : String
  content : String
  /// 工具结果专用:关联的 tool_use_id(None 表示普通消息)
  tool_use_id : String?
  /// 工具结果专用:是否执行出错(默认 false)
  is_error : Bool?
  /// assistant 工具调用专用:空数组表示普通消息(见 SdkMessage::tool_call)
  tool_calls : Array[SdkToolCall]
}

///|
pub fn SdkMessage::new(role : String, content : String) -> SdkMessage {
  { role, content, tool_use_id: None, is_error: None, tool_calls: [], }
}

///|
/// 构造工具结果消息(Agent 循环注入工具执行结果用)
pub fn SdkMessage::tool_result(
  tool_use_id : String,
  content : String,
  is_error : Bool,
) -> SdkMessage {
  {
    role: "tool",
    content,
    tool_use_id: Some(tool_use_id),
    is_error: Some(is_error),
    tool_calls: [],
  }
}

///|
/// 构造 assistant 工具调用消息(Agent 循环第一轮回填用,单个调用)
///
/// role 固定为 "assistant";content 可携带同回合的文本(混合输出)。
pub fn SdkMessage::tool_call(
  id : String,
  name : String,
  arguments_json : String,
  content : String,
) -> SdkMessage {
  SdkMessage::assistant_turn(content, [
    SdkToolCall::new(id, name, arguments_json),
  ])
}

///|
/// 构造 assistant 回合消息(文本 + 任意数量工具调用合并为一条消息)
///
/// 回合级语义:一个 assistant 回合的文本与全部 tool_use 必须在同一条
/// 消息里,provider(Anthropic/OpenAI)才接受紧随其后的 tool_result。
pub fn SdkMessage::assistant_turn(
  content : String,
  tool_calls : Array[SdkToolCall],
) -> SdkMessage {
  { role: "assistant", content, tool_use_id: None, is_error: None, tool_calls, }
}

///|
/// SdkTool — SDK 层的工具定义
pub struct SdkTool {
  name : String
  description : String
  parameters_json : String
}

///|
pub fn SdkTool::new(
  name : String,
  description : String,
  parameters_json : String,
) -> SdkTool {
  { name, description, parameters_json, }
}

///|
/// Context — 对话上下文
pub struct Context {
  system_prompt : String?
  messages : Array[SdkMessage]
  tools : Array[SdkTool]?
}

///|
pub fn Context::new() -> Context {
  { system_prompt: None, messages: [], tools: None, }
}

///|
/// 设置系统指令
pub fn Context::add_system(self : Context, prompt : String) -> Context {
  { ..self, system_prompt: Some(prompt), }
}

///|
/// 添加用户消息
pub fn Context::add_user(self : Context, text : String) -> Context {
  self.push_msg(SdkMessage::new("user", text))
}

///|
/// 添加助手消息
pub fn Context::add_assistant(self : Context, text : String) -> Context {
  self.push_msg(SdkMessage::new("assistant", text))
}

///|
/// 添加工具
pub fn Context::add_tools(self : Context, tools : Array[SdkTool]) -> Context {
  { ..self, tools: Some(tools), }
}

///|

///|
/// 内部辅助:追加消息并返回新 Context(消除 add_* 中的 copy+push 样板)
fn Context::push_msg(self : Context, msg : SdkMessage) -> Context {
  let new_msgs = self.messages.copy()
  new_msgs.push(msg)
  { ..self, messages: new_msgs, }
}

///|
/// 注入工具执行结果(Agent 循环:执行工具后继续对话)
pub fn Context::add_tool_result(
  self : Context,
  tool_use_id : String,
  content : String,
  is_error : Bool,
) -> Context {
  self.push_msg(SdkMessage::tool_result(tool_use_id, content, is_error))
}

///|
/// 回填 assistant 工具调用回合(Agent 循环:模型要求调用工具后、
/// 注入 tool_result 之前,必须先补这一回合,否则第二轮请求会被
/// provider 拒绝——tool_result 必须紧跟含 tool_use 的 assistant 消息)
pub fn Context::add_tool_call(
  self : Context,
  id : String,
  name : String,
  arguments_json : String,
  content : String,
) -> Context {
  self.push_msg(SdkMessage::tool_call(id, name, arguments_json, content))
}

///|
/// 回填整个 assistant 回合(文本 + 任意数量工具调用合并为一条消息)
///
/// Agent 循环回填闭环用:`Prism::events_to_context` 内部调用。
pub fn Context::add_assistant_turn(
  self : Context,
  text : String,
  tool_calls : Array[SdkToolCall],
) -> Context {
  self.push_msg(SdkMessage::assistant_turn(text, tool_calls))
}

///|
/// 将 Context 转为 LucentRequest(SDK 内部使用)
pub fn context_to_lux_request(
  ctx : Context,
  model : String,
  opts : PrismOptions,
) -> @lux.LucentRequest {
  let items : Array[@lux.LucentConversationItem] = []
  for msg in ctx.messages {
    match msg.tool_use_id {
      Some(id) => {
        // 工具结果消息 → Item::ToolResult(Agent 循环注入)
        let is_err = match msg.is_error {
          Some(b) => b
          None => false
        }
        items.push(
          @lux.LucentConversationItem::tool_result(
            @lux.LucentToolResult::new(
              id,
              [@lux.LucentContent::text(msg.content)],
              is_err,
            ),
          ),
        )
      }
      None =>
        // assistant 工具调用回合 → Message{Assistant, [Text?, ToolUse...]}
        // 与 provider 入站解码形态一致(openai append_tool_calls)
        if msg.tool_calls.length() > 0 {
          let content : Array[@lux.LucentContent] = []
          if msg.content != "" {
            content.push(@lux.LucentContent::text(msg.content))
          }
          for tc in msg.tool_calls {
            content.push(
              @lux.LucentContent::tool_use(
                tc.id,
                tc.name,
                tc.arguments_json,
                None,
              ),
            )
          }
          let lmsg = @lux.LucentMessage::new(Assistant, content)
          items.push(@lux.LucentConversationItem::message(lmsg))
        } else {
          let role = match msg.role {
            "system" => @lux.System
            "user" => User
            "assistant" => Assistant
            "tool" => Tool
            _ => User
          }
          let content = [@lux.LucentContent::text(msg.content)]
          let lmsg = @lux.LucentMessage::new(role, content)
          items.push(@lux.LucentConversationItem::message(lmsg))
        }
    }
  }
  let tools_arr = match ctx.tools {
    Some(tools) => {
      let arr : Array[@lux.LucentTool] = []
      for t in tools {
        arr.push(
          @lux.LucentTool::simple(t.name, t.description, t.parameters_json),
        )
      }
      Some(arr)
    }
    None => None
  }
  let lux_opts = @lux.LucentOptions::new(
    opts.temperature,
    None,
    None,
    opts.max_tokens,
    None,
    false,
    None,
    opts.structured_output,
    opts.store,
    // parallel_tool_calls 经 extras 语义反传(openai 直接消费;
    // messages 消费反向的 disable_parallel_tool_use,由编码端换算)
    merge_parallel_tool_extras(opts),
  )
  // reasoning:显式关闭优先;否则 effort 或 enabled 任一设置即启用
  let reasoning : @lux.LucentReasoningConfig? = match opts.reasoning_enabled {
    Some(false) => Some(@lux.LucentReasoningConfig::disabled())
    _ =>
      if opts.reasoning_enabled is None && opts.reasoning_effort is None {
        None
      } else {
        Some(@lux.LucentReasoningConfig::new(opts.reasoning_effort, None))
      }
  }
  @lux.LucentRequest::new(
    model,
    match ctx.system_prompt {
      Some(s) => Some([@lux.LucentContent::text(s)])
      None => None
    },
    items,
    tools_arr,
    opts.tool_choice,
    lux_opts,
    None,
    reasoning,
    None,
    None,
  )
}

///|
/// 合并 parallel_tool_calls 到 extras(T3)
///
/// 用户 extras 优先保留;parallel_tool_calls 仅在用户未显式设置同名键时
/// 注入(Extension 字段规则:可选、不覆盖用户数据)。未设置时原样返回
/// 用户 extras——保证缺省路径输出不变。
fn merge_parallel_tool_extras(opts : PrismOptions) -> Map[String, Json]? {
  match opts.parallel_tool_calls {
    None => opts.extras
    Some(enabled) => {
      let merged : Map[String, Json] = match opts.extras {
        Some(m) => m.copy()
        None => Map([])
      }
      // 用户已显式通过 extras 设置则不覆盖
      match merged.get("parallel_tool_calls") {
        Some(_) => Some(merged)
        None => {
          merged["parallel_tool_calls"] = Json::boolean(enabled)
          Some(merged)
        }
      }
    }
  }
}