//// A refused retrieval call answers with an error payload the model can
//// correct, instead of ending the turn: subagents died whole on
//// "run failed: LCM node not found in this session" after handing a
//// transcript row seq to an LCM node tool.

import albedo/daemon/conversation
import albedo/harness/extensions
import albedo/harness/extensions/lcm/memory as lcm_memory
import albedo/harness/runtime
import albedo/openai_api/types
import gleam/dynamic/decode
import gleam/json
import gleam/option.{None}
import gleam/string
import gleeunit/should

fn host() -> #(runtime.Runtime, runtime.Session) {
  let assert Ok(host) =
    runtime.start_with_config(
      ":memory:",
      extensions.Config([lcm_memory.extension()], ["lcm-memory"]),
    )
  let ledger = runtime.ledger(host)
  let assert Ok(_) = conversation.initialise(ledger)
  let assert Ok(_) =
    conversation.create(
      ledger,
      conversation.Info(
        "tool-error-test",
        "new session",
        "/tmp",
        "provider",
        "model",
        types.Responses,
        conversation.Idle,
        None,
        None,
      ),
    )
  let assert Ok(session) = runtime.open_session(host, "tool-error-test", "/tmp")
  #(host, session)
}

fn answer(
  host: runtime.Runtime,
  session: runtime.Session,
  name: String,
  arguments: String,
) -> String {
  // The regression is Ok against Error: a refused read must not fail the run.
  let assert Ok(output) =
    runtime.invoke(
      host,
      session,
      types.ToolCall("call_1", name, arguments),
      types.any_images,
    )
  let assert types.ToolOutput(_, body, []) = output
  body
}

pub fn missing_lcm_node_answers_as_tool_output_test() -> Nil {
  let #(host, session) = host()
  // 35049 is a transcript row seq, the exact confusion that killed a child.
  let body = answer(host, session, "lcm_describe", "{\"id\":35049}")
  let assert Ok(reason) =
    json.parse(body, decode.field("error", decode.string, decode.success))
  string.contains(reason, "LCM node 35049 not found") |> should.be_true
  string.contains(reason, "transcript_read") |> should.be_true
  runtime.stop(host)
}

pub fn missing_summary_scope_answers_as_tool_output_test() -> Nil {
  let #(host, session) = host()
  let body =
    answer(
      host,
      session,
      "lcm_grep",
      "{\"pattern\":\"needle\",\"summary_id\":7}",
    )
  let assert Ok(reason) =
    json.parse(body, decode.field("error", decode.string, decode.success))
  string.contains(reason, "LCM node 7 not found") |> should.be_true
  runtime.stop(host)
}

pub fn answering_tools_still_answer_normally_test() -> Nil {
  let #(host, session) = host()
  let body = answer(host, session, "lcm_list", "{}")
  let assert Ok(total) =
    json.parse(body, decode.field("total", decode.int, decode.success))
  total |> should.equal(0)
  runtime.stop(host)
}
