// OpenCode's canonical JSONL event mapping:
// https://github.com/anomalyco/opencode/blob/1e17856ba4b5b052650c8115060852f3f023844e/packages/opencode/src/cli/cmd/run.ts#L678-L794

///|
fn moonbit_internal_thread_event_from_json(
  json : Json,
) -> ThreadEvent raise OpenCodeSdkError {
  let object = moonbit_internal_json_object(json, "thread event")
  let event_type = moonbit_internal_required_string(
    object, "type", "thread event",
  )
  let session_id = moonbit_internal_required_string(
    object, "sessionID", "thread event",
  )
  match event_type {
    "text" => {
      let part = moonbit_internal_json_object(
        moonbit_internal_required_json(object, "part", event_type),
        "\{event_type}.part",
      )
      Text({
        session_id,
        text: moonbit_internal_required_string(
          part,
          "text",
          "\{event_type}.part",
        ),
      })
    }
    "reasoning" => {
      let part = moonbit_internal_json_object(
        moonbit_internal_required_json(object, "part", event_type),
        "\{event_type}.part",
      )
      Reasoning({
        session_id,
        text: moonbit_internal_required_string(
          part,
          "text",
          "\{event_type}.part",
        ),
      })
    }
    "tool_use" => {
      let part = moonbit_internal_json_object(
        moonbit_internal_required_json(object, "part", event_type),
        "\{event_type}.part",
      )
      let state = moonbit_internal_json_object(
        moonbit_internal_required_json(part, "state", "\{event_type}.part"),
        "\{event_type}.part.state",
      )
      let status = match
        moonbit_internal_required_string(
          state,
          "status",
          "\{event_type}.part.state",
        ) {
        "completed" => ToolUseStatus::Completed
        "error" => ToolUseStatus::Failed
        status =>
          raise InvalidEvent(message="unsupported tool-use status: \{status}")
      }
      ToolUse({
        session_id,
        call_id: moonbit_internal_required_string(
          part,
          "callID",
          "\{event_type}.part",
        ),
        tool: moonbit_internal_required_string(
          part,
          "tool",
          "\{event_type}.part",
        ),
        status,
      })
    }
    "step_start" => StepStart({ session_id, })
    "step_finish" => {
      let part = moonbit_internal_json_object(
        moonbit_internal_required_json(object, "part", event_type),
        "\{event_type}.part",
      )
      let tokens = moonbit_internal_json_object(
        moonbit_internal_required_json(part, "tokens", "\{event_type}.part"),
        "\{event_type}.part.tokens",
      )
      let cache = moonbit_internal_json_object(
        moonbit_internal_required_json(
          tokens,
          "cache",
          "\{event_type}.part.tokens",
        ),
        "\{event_type}.part.tokens.cache",
      )
      StepFinish({
        session_id,
        reason: moonbit_internal_required_string(
          part,
          "reason",
          "\{event_type}.part",
        ),
        cost: moonbit_internal_required_double(
          part,
          "cost",
          "\{event_type}.part",
        ),
        usage: {
          input_tokens: moonbit_internal_required_int(
            tokens,
            "input",
            "\{event_type}.part.tokens",
          ),
          output_tokens: moonbit_internal_required_int(
            tokens,
            "output",
            "\{event_type}.part.tokens",
          ),
          reasoning_tokens: moonbit_internal_required_int(
            tokens,
            "reasoning",
            "\{event_type}.part.tokens",
          ),
          cache_read_tokens: moonbit_internal_required_int(
            cache,
            "read",
            "\{event_type}.part.tokens.cache",
          ),
          cache_write_tokens: moonbit_internal_required_int(
            cache,
            "write",
            "\{event_type}.part.tokens.cache",
          ),
        },
      })
    }
    "error" => {
      let error = moonbit_internal_json_object(
        moonbit_internal_required_json(object, "error", event_type),
        "\{event_type}.error",
      )
      let name = moonbit_internal_required_string(
        error,
        "name",
        "\{event_type}.error",
      )
      let message = @lens.object("data")
        .string("message")
        .get(Json::object(error)) catch {
          _ => name
        }
      StreamError({ session_id: Some(session_id), message })
    }
    _ =>
      raise InvalidEvent(message="unsupported thread event type: \{event_type}")
  }
}