Skip to main content

lib/jido/chat/thread_summary.ex

defmodule Jido.Chat.ThreadSummary do
  @moduledoc """
  Lightweight thread descriptor for channel-level thread listing.
  """

  alias Jido.Chat.{Incoming, Message}

  @schema Zoi.struct(
            __MODULE__,
            %{
              id: Zoi.string(),
              last_reply_at: Zoi.any() |> Zoi.nullish(),
              reply_count: Zoi.integer() |> Zoi.nullish(),
              root_message: Zoi.struct(Message) |> Zoi.nullish(),
              metadata: Zoi.map() |> Zoi.default(%{})
            },
            coerce: true
          )

  @type t :: unquote(Zoi.type_spec(@schema))

  @enforce_keys Zoi.Struct.enforce_keys(@schema)
  defstruct Zoi.Struct.struct_fields(@schema)

  @doc "Returns the Zoi schema for ThreadSummary."
  def schema, do: @schema

  @doc "Creates a thread summary and normalizes root message payload."
  def new(attrs) when is_map(attrs) do
    attrs
    |> normalize_root_message()
    |> then(&Jido.Chat.Schema.parse!(__MODULE__, @schema, &1))
  end

  defp normalize_root_message(attrs) do
    case attrs[:root_message] || attrs["root_message"] do
      %Message{} ->
        attrs

      %Incoming{} = incoming ->
        Map.put(attrs, :root_message, Message.from_incoming(incoming))

      nil ->
        attrs

      map when is_map(map) ->
        if Map.has_key?(map, :external_room_id) || Map.has_key?(map, "external_room_id") do
          message = map |> Incoming.new() |> Message.from_incoming()
          Map.put(attrs, :root_message, message)
        else
          Map.put(attrs, :root_message, Message.new(map))
        end

      _other ->
        attrs
    end
  end
end