-- name: CreateMessage :one
INSERT INTO messages (channel_id, user_id, content, reply_to) VALUES (?, ?, ?, ?)
RETURNING id, channel_id, user_id, content, reply_to, edited_at, deleted, pinned, timestamp,
          mentions_everyone;

-- name: GetMessage :one
SELECT id, channel_id, user_id, content, reply_to, edited_at, deleted, pinned, timestamp,
       mentions_everyone
FROM messages WHERE id = ?;

-- name: GetMessagesForAPI :many
SELECT m.id, m.channel_id, m.user_id, u.username, u.avatar,
       m.content, m.reply_to, m.edited_at, m.deleted, m.pinned, m.timestamp
FROM messages m JOIN users u ON m.user_id = u.id
WHERE m.channel_id = ? AND m.deleted = 0
ORDER BY m.id DESC LIMIT ?;

-- name: EditMessageContent :one
UPDATE messages SET content = ?, edited_at = datetime('now') WHERE id = ?
RETURNING id, channel_id, user_id, content, reply_to, edited_at, deleted, pinned, timestamp,
          mentions_everyone;

-- name: SoftDeleteMessage :exec
UPDATE messages SET deleted = 1 WHERE id = ?;

-- name: SetMessagePinned :execresult
UPDATE messages SET pinned = ? WHERE id = ? AND deleted = 0;

-- name: GetLatestMessageID :one
SELECT COALESCE(MAX(id), 0) FROM messages WHERE channel_id = ? AND deleted = 0;

-- name: UpdateReadState :exec
-- Marking a channel read also clears its mention badge: channel_focus is the
-- only caller, and a focused channel has no outstanding mentions by definition.
INSERT INTO read_states (user_id, channel_id, last_message_id, mention_count)
VALUES (?, ?, ?, 0)
ON CONFLICT(user_id, channel_id) DO UPDATE SET
    last_message_id = excluded.last_message_id,
    mention_count = 0;

-- name: GetReadState :one
-- Reader-pool lookup that lets the channel-focus path skip the UpdateReadState
-- UPSERT when the row is already correct, keeping no-op focus events off the
-- single writer connection.
SELECT last_message_id, mention_count FROM read_states
 WHERE user_id = ? AND channel_id = ?;

-- name: GetChannelUnreadCounts :many
SELECT c.id,
       (SELECT COALESCE(MAX(m.id), 0) FROM messages m
         WHERE m.channel_id = c.id AND m.deleted = 0) AS last_msg_id,
       (SELECT COUNT(*) FROM messages m
         WHERE m.channel_id = c.id AND m.deleted = 0
           AND m.id > COALESCE((SELECT rs.last_message_id FROM read_states rs
                                 WHERE rs.channel_id = c.id AND rs.user_id = ?), 0)) AS unread,
       COALESCE((SELECT rs.mention_count FROM read_states rs
                  WHERE rs.channel_id = c.id AND rs.user_id = ?), 0) AS mentions
FROM channels c
WHERE c.type IN ('text', 'announcement')
   OR (c.type = 'dm' AND EXISTS (SELECT 1 FROM dm_participants dp
                                  WHERE dp.channel_id = c.id AND dp.user_id = ?));

-- SearchMessages and SearchMessagesInChannel use the messages_fts FTS5 virtual
-- table which sqlc cannot introspect. Those queries remain as hand-written Go
-- in message_queries.go.
