# `ExWapp.Chat`
[🔗](https://github.com/elchemista/ex_wapp/blob/v0.1.5/lib/ex_wapp/chat.ex#L1)

Chat and conversation management.

This module handles:
- Storing and retrieving conversations
- Managing chat history
- Tracking message state (read, delivered, etc.)

## Storage

Chats are persisted via the session's store adapter. The chat data is stored
under the `:chats` key in the store.

## Usage

    # Get all chats from session
    chats = ExWapp.Chat.list(session)

    # Get a specific chat
    {:ok, chat} = ExWapp.Chat.get(session, "1234567890@s.whatsapp.net")

    # Get messages for a chat
    messages = ExWapp.Chat.messages(session, "1234567890@s.whatsapp.net")

# `chat`

```elixir
@type chat() :: %ExWapp.Chat{
  archived: boolean(),
  is_group: boolean(),
  jid: String.t(),
  last_message_timestamp: integer() | nil,
  muted_until: integer() | nil,
  name: String.t() | nil,
  pinned: boolean(),
  unread_count: non_neg_integer()
}
```

# `message`

```elixir
@type message() :: %{
  :id =&gt; String.t(),
  :from_me =&gt; boolean(),
  :timestamp =&gt; integer(),
  :text =&gt; String.t() | nil,
  :status =&gt; message_status(),
  :participant =&gt; String.t() | ExWapp.JID.t() | nil,
  :raw =&gt; map() | nil,
  optional(:content) =&gt; term(),
  optional(:media) =&gt; term(),
  optional(:location) =&gt; term(),
  optional(:contact) =&gt; term(),
  optional(:event) =&gt; term()
}
```

# `message_status`

```elixir
@type message_status() :: :pending | :sent | :received | :delivered | :read | :failed
```

# `target`

```elixir
@type target() :: pid() | struct()
```

# `add_message`

```elixir
@spec add_message(target(), String.t() | ExWapp.JID.t(), message()) ::
  :ok | {:error, term()}
```

Adds a message to a chat.

# `all_messages`

```elixir
@spec all_messages(target(), String.t() | ExWapp.JID.t(), keyword()) :: Enumerable.t()
```

Returns a lazy stream over every locally retained message, oldest first.

# `archive`

```elixir
@spec archive(target(), String.t()) :: :ok
```

Archives a chat.

# `delete`

```elixir
@spec delete(target(), String.t()) :: :ok | {:error, term()}
```

Deletes a chat.

# `delete_messages`

```elixir
@spec delete_messages(target(), String.t() | ExWapp.JID.t(), [String.t()]) ::
  :ok | {:error, term()}
```

Deletes selected local messages after they have been persisted elsewhere.

# `find_message`

```elixir
@spec find_message(target(), String.t() | ExWapp.JID.t(), String.t()) ::
  message() | nil
```

Finds one locally stored message in a chat.

# `find_message_by_id`

```elixir
@spec find_message_by_id(target(), String.t()) :: {String.t(), message()} | nil
```

Finds one locally stored message by ID across all chats.

# `get`

```elixir
@spec get(target(), String.t() | ExWapp.JID.t()) ::
  {:ok, chat()} | {:error, :not_found}
```

Gets a specific chat by JID.

# `get_or_create`

```elixir
@spec get_or_create(target(), String.t() | ExWapp.JID.t(), keyword()) :: chat()
```

Gets or creates a chat for a JID.

# `list`

```elixir
@spec list(target()) :: [chat()]
```

Lists all chats for a session.

Returns a list of chat structs sorted by last message timestamp (most recent first).

# `list_groups`

```elixir
@spec list_groups(target()) :: [chat()]
```

Lists only group chats for a session.

# `mark_read`

```elixir
@spec mark_read(target(), String.t() | ExWapp.JID.t()) :: :ok
```

Marks all messages in a chat as read.

# `mark_read_from_sync`

```elixir
@spec mark_read_from_sync(target(), String.t(), map()) :: :ok
```

Mark chat as read/unread from app state sync dispatch.

# `merge_messages`

```elixir
@spec merge_messages(target(), String.t() | ExWapp.JID.t(), [message()]) ::
  :ok | {:error, term()}
```

Merges a batch of messages into a chat, deduplicating by message ID.

# `merge_metadata`

```elixir
@spec merge_metadata(target(), String.t() | ExWapp.JID.t(), map() | keyword()) :: :ok
```

Upserts metadata fields for a chat from sync/notification payloads.

Supported keys:
- `:name`
- `:unread_count`
- `:last_message_timestamp`
- `:pinned`
- `:muted_until`
- `:archived`
- `:is_group`

# `messages`

```elixir
@spec messages(target(), String.t() | ExWapp.JID.t(), keyword()) :: [message()]
```

Gets a materialized page of locally retained messages, newest first.

Message payloads live in the configured message store rather than in the
chat struct. Use stream_messages/3 for an unbounded, lazy traversal.

# `new_chat`

```elixir
@spec new_chat(String.t(), keyword()) :: chat()
```

Creates a new chat struct.

# `parse_message_node`

```elixir
@spec parse_message_node(ExWapp.Binary.Node.t()) ::
  {:ok, String.t(), message()} | {:error, term()}
```

Parses a received message node into a message struct.

# `pin`

```elixir
@spec pin(target(), String.t()) :: :ok
```

Pins a chat.

# `stream_messages`

```elixir
@spec stream_messages(target(), String.t() | ExWapp.JID.t(), keyword()) ::
  Enumerable.t()
```

Builds a lazy stream over locally retained messages.

The default order is oldest first so a wrapper can persist history in
chronological order. The stream reads one indexed record at a time and does
not first load the complete chat history.

This is local history only; it does not request older messages from WhatsApp.

# `unarchive`

```elixir
@spec unarchive(target(), String.t()) :: :ok
```

Unarchives a chat.

# `unpin`

```elixir
@spec unpin(target(), String.t()) :: :ok
```

Unpins a chat.

# `update_archived`

```elixir
@spec update_archived(target(), String.t(), boolean()) :: :ok
```

Update archived state from app state sync dispatch.

# `update_message_status`

```elixir
@spec update_message_status(
  target(),
  String.t() | ExWapp.JID.t(),
  String.t(),
  message_status()
) ::
  :ok | {:error, term()}
```

Updates a message status.

# `update_message_status_by_id`

```elixir
@spec update_message_status_by_id(target(), String.t(), message_status()) ::
  :ok | {:error, term()}
```

Updates a message status by message ID across all chats.

Useful for ACK nodes that do not provide a chat JID we can trust.

# `update_muted`

```elixir
@spec update_muted(target(), String.t(), map()) :: :ok
```

Update muted state from app state sync dispatch.

# `update_name`

```elixir
@spec update_name(target(), String.t(), String.t()) :: :ok
```

Updates the chat name (for contacts that send push names).

# `update_pinned`

```elixir
@spec update_pinned(target(), String.t(), boolean()) :: :ok
```

Update pinned state from app state sync dispatch.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
