defmodule Jido.Chat.Telegram.CallbackQuery do
@moduledoc """
Typed callback query payload for Telegram action-style updates.
"""
alias Jido.Chat.Author
alias Jido.Chat.Wire
@schema Zoi.struct(
__MODULE__,
%{
id: Zoi.string(),
data: Zoi.string() |> Zoi.nullish(),
from: Zoi.struct(Author) |> Zoi.nullish(),
chat_id: Zoi.any() |> Zoi.nullish(),
message_id: Zoi.any() |> Zoi.nullish(),
inline_message_id: Zoi.string() |> Zoi.nullish(),
raw: 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 CallbackQuery."
def schema, do: @schema
@doc "Creates a typed callback query struct."
@spec new(map()) :: t()
def new(attrs) when is_map(attrs) do
attrs
|> normalize_from()
|> then(&Jido.Chat.Schema.parse!(__MODULE__, @schema, &1))
end
@doc "Serializes callback query into a plain map with type marker."
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = callback_query) do
callback_query
|> Map.from_struct()
|> Wire.to_plain()
|> Map.put("__type__", "telegram_callback_query")
end
@doc "Builds callback query from serialized map data."
@spec from_map(map()) :: t()
def from_map(map) when is_map(map), do: new(map)
defp normalize_from(attrs) do
from = attrs[:from] || attrs["from"]
author =
case from do
%Author{} = author ->
author
map when is_map(map) ->
Author.new(%{
user_id: to_string(map[:id] || map["id"] || "unknown"),
user_name: map[:username] || map["username"] || to_string(map[:id] || map["id"] || "unknown"),
full_name: map[:first_name] || map["first_name"],
is_bot: map[:is_bot] || map["is_bot"] || false
})
_ ->
nil
end
if is_nil(author), do: attrs, else: Map.put(attrs, :from, author)
end
end