// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.30.0
// source: messages.sql

package sqlc

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
)

const createMessage = `-- name: CreateMessage :one
INSERT INTO bot_history_messages (
  bot_id,
  session_id,
  sender_channel_identity_id,
  sender_account_user_id,
  source_message_id,
  source_reply_to_message_id,
  role,
  content,
  metadata,
  usage,
  model_id
)
VALUES (
  $1,
  $2::uuid,
  $3::uuid,
  $4::uuid,
  $5::text,
  $6::text,
  $7,
  $8,
  $9,
  $10,
  $11::uuid
)
RETURNING
  id,
  bot_id,
  session_id,
  sender_channel_identity_id,
  sender_account_user_id AS sender_user_id,
  source_message_id AS external_message_id,
  source_reply_to_message_id,
  role,
  content,
  metadata,
  usage,
  created_at
`

type CreateMessageParams struct {
	BotID                   pgtype.UUID `json:"bot_id"`
	SessionID               pgtype.UUID `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text `json:"source_reply_to_message_id"`
	Role                    string      `json:"role"`
	Content                 []byte      `json:"content"`
	Metadata                []byte      `json:"metadata"`
	Usage                   []byte      `json:"usage"`
	ModelID                 pgtype.UUID `json:"model_id"`
}

type CreateMessageRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
}

func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (CreateMessageRow, error) {
	row := q.db.QueryRow(ctx, createMessage,
		arg.BotID,
		arg.SessionID,
		arg.SenderChannelIdentityID,
		arg.SenderUserID,
		arg.ExternalMessageID,
		arg.SourceReplyToMessageID,
		arg.Role,
		arg.Content,
		arg.Metadata,
		arg.Usage,
		arg.ModelID,
	)
	var i CreateMessageRow
	err := row.Scan(
		&i.ID,
		&i.BotID,
		&i.SessionID,
		&i.SenderChannelIdentityID,
		&i.SenderUserID,
		&i.ExternalMessageID,
		&i.SourceReplyToMessageID,
		&i.Role,
		&i.Content,
		&i.Metadata,
		&i.Usage,
		&i.CreatedAt,
	)
	return i, err
}

const deleteMessagesByBot = `-- name: DeleteMessagesByBot :exec
DELETE FROM bot_history_messages
WHERE bot_id = $1
`

func (q *Queries) DeleteMessagesByBot(ctx context.Context, botID pgtype.UUID) error {
	_, err := q.db.Exec(ctx, deleteMessagesByBot, botID)
	return err
}

const deleteMessagesBySession = `-- name: DeleteMessagesBySession :exec
DELETE FROM bot_history_messages
WHERE session_id = $1
`

func (q *Queries) DeleteMessagesBySession(ctx context.Context, sessionID pgtype.UUID) error {
	_, err := q.db.Exec(ctx, deleteMessagesBySession, sessionID)
	return err
}

const listActiveMessagesSince = `-- name: ListActiveMessagesSince :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.compact_id,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.bot_id = $1
  AND m.created_at >= $2
  AND (m.metadata->>'trigger_mode' IS NULL OR m.metadata->>'trigger_mode' != 'passive_sync')
ORDER BY m.created_at ASC
`

type ListActiveMessagesSinceParams struct {
	BotID     pgtype.UUID        `json:"bot_id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
}

type ListActiveMessagesSinceRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CompactID               pgtype.UUID        `json:"compact_id"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListActiveMessagesSince(ctx context.Context, arg ListActiveMessagesSinceParams) ([]ListActiveMessagesSinceRow, error) {
	rows, err := q.db.Query(ctx, listActiveMessagesSince, arg.BotID, arg.CreatedAt)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListActiveMessagesSinceRow
	for rows.Next() {
		var i ListActiveMessagesSinceRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CompactID,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listActiveMessagesSinceBySession = `-- name: ListActiveMessagesSinceBySession :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.compact_id,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.session_id = $1
  AND m.created_at >= $2
  AND (m.metadata->>'trigger_mode' IS NULL OR m.metadata->>'trigger_mode' != 'passive_sync')
ORDER BY m.created_at ASC
`

type ListActiveMessagesSinceBySessionParams struct {
	SessionID pgtype.UUID        `json:"session_id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
}

type ListActiveMessagesSinceBySessionRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CompactID               pgtype.UUID        `json:"compact_id"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListActiveMessagesSinceBySession(ctx context.Context, arg ListActiveMessagesSinceBySessionParams) ([]ListActiveMessagesSinceBySessionRow, error) {
	rows, err := q.db.Query(ctx, listActiveMessagesSinceBySession, arg.SessionID, arg.CreatedAt)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListActiveMessagesSinceBySessionRow
	for rows.Next() {
		var i ListActiveMessagesSinceBySessionRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CompactID,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessages = `-- name: ListMessages :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.bot_id = $1
ORDER BY m.created_at ASC
LIMIT 10000
`

type ListMessagesRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessages(ctx context.Context, botID pgtype.UUID) ([]ListMessagesRow, error) {
	rows, err := q.db.Query(ctx, listMessages, botID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesRow
	for rows.Next() {
		var i ListMessagesRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesBefore = `-- name: ListMessagesBefore :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.bot_id = $1
  AND m.created_at < $2
ORDER BY m.created_at DESC
LIMIT $3
`

type ListMessagesBeforeParams struct {
	BotID     pgtype.UUID        `json:"bot_id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
	MaxCount  int32              `json:"max_count"`
}

type ListMessagesBeforeRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesBefore(ctx context.Context, arg ListMessagesBeforeParams) ([]ListMessagesBeforeRow, error) {
	rows, err := q.db.Query(ctx, listMessagesBefore, arg.BotID, arg.CreatedAt, arg.MaxCount)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesBeforeRow
	for rows.Next() {
		var i ListMessagesBeforeRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesBeforeBySession = `-- name: ListMessagesBeforeBySession :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.session_id = $1
  AND m.created_at < $2
ORDER BY m.created_at DESC
LIMIT $3
`

type ListMessagesBeforeBySessionParams struct {
	SessionID pgtype.UUID        `json:"session_id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
	MaxCount  int32              `json:"max_count"`
}

type ListMessagesBeforeBySessionRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesBeforeBySession(ctx context.Context, arg ListMessagesBeforeBySessionParams) ([]ListMessagesBeforeBySessionRow, error) {
	rows, err := q.db.Query(ctx, listMessagesBeforeBySession, arg.SessionID, arg.CreatedAt, arg.MaxCount)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesBeforeBySessionRow
	for rows.Next() {
		var i ListMessagesBeforeBySessionRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesBySession = `-- name: ListMessagesBySession :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.session_id = $1
ORDER BY m.created_at ASC
LIMIT 10000
`

type ListMessagesBySessionRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesBySession(ctx context.Context, sessionID pgtype.UUID) ([]ListMessagesBySessionRow, error) {
	rows, err := q.db.Query(ctx, listMessagesBySession, sessionID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesBySessionRow
	for rows.Next() {
		var i ListMessagesBySessionRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesLatest = `-- name: ListMessagesLatest :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.bot_id = $1
ORDER BY m.created_at DESC
LIMIT $2
`

type ListMessagesLatestParams struct {
	BotID    pgtype.UUID `json:"bot_id"`
	MaxCount int32       `json:"max_count"`
}

type ListMessagesLatestRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesLatest(ctx context.Context, arg ListMessagesLatestParams) ([]ListMessagesLatestRow, error) {
	rows, err := q.db.Query(ctx, listMessagesLatest, arg.BotID, arg.MaxCount)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesLatestRow
	for rows.Next() {
		var i ListMessagesLatestRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesLatestBySession = `-- name: ListMessagesLatestBySession :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.session_id = $1
ORDER BY m.created_at DESC
LIMIT $2
`

type ListMessagesLatestBySessionParams struct {
	SessionID pgtype.UUID `json:"session_id"`
	MaxCount  int32       `json:"max_count"`
}

type ListMessagesLatestBySessionRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesLatestBySession(ctx context.Context, arg ListMessagesLatestBySessionParams) ([]ListMessagesLatestBySessionRow, error) {
	rows, err := q.db.Query(ctx, listMessagesLatestBySession, arg.SessionID, arg.MaxCount)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesLatestBySessionRow
	for rows.Next() {
		var i ListMessagesLatestBySessionRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesSince = `-- name: ListMessagesSince :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.bot_id = $1
  AND m.created_at >= $2
ORDER BY m.created_at ASC
`

type ListMessagesSinceParams struct {
	BotID     pgtype.UUID        `json:"bot_id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
}

type ListMessagesSinceRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesSince(ctx context.Context, arg ListMessagesSinceParams) ([]ListMessagesSinceRow, error) {
	rows, err := q.db.Query(ctx, listMessagesSince, arg.BotID, arg.CreatedAt)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesSinceRow
	for rows.Next() {
		var i ListMessagesSinceRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listMessagesSinceBySession = `-- name: ListMessagesSinceBySession :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.sender_account_user_id AS sender_user_id,
  m.source_message_id AS external_message_id,
  m.source_reply_to_message_id,
  m.role,
  m.content,
  m.metadata,
  m.usage,
  m.created_at,
  ci.display_name AS sender_display_name,
  ci.avatar_url AS sender_avatar_url,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.session_id = $1
  AND m.created_at >= $2
ORDER BY m.created_at ASC
`

type ListMessagesSinceBySessionParams struct {
	SessionID pgtype.UUID        `json:"session_id"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
}

type ListMessagesSinceBySessionRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	SenderUserID            pgtype.UUID        `json:"sender_user_id"`
	ExternalMessageID       pgtype.Text        `json:"external_message_id"`
	SourceReplyToMessageID  pgtype.Text        `json:"source_reply_to_message_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Metadata                []byte             `json:"metadata"`
	Usage                   []byte             `json:"usage"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	SenderAvatarUrl         pgtype.Text        `json:"sender_avatar_url"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) ListMessagesSinceBySession(ctx context.Context, arg ListMessagesSinceBySessionParams) ([]ListMessagesSinceBySessionRow, error) {
	rows, err := q.db.Query(ctx, listMessagesSinceBySession, arg.SessionID, arg.CreatedAt)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListMessagesSinceBySessionRow
	for rows.Next() {
		var i ListMessagesSinceBySessionRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.SenderUserID,
			&i.ExternalMessageID,
			&i.SourceReplyToMessageID,
			&i.Role,
			&i.Content,
			&i.Metadata,
			&i.Usage,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.SenderAvatarUrl,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listObservedConversationsByChannelIdentity = `-- name: ListObservedConversationsByChannelIdentity :many
WITH observed_routes AS (
  SELECT
    s.route_id,
    MAX(m.created_at)::timestamptz AS last_observed_at
  FROM bot_history_messages m
  JOIN bot_sessions s ON s.id = m.session_id
  WHERE m.bot_id = $1
    AND m.sender_channel_identity_id = $2::uuid
    AND s.route_id IS NOT NULL
  GROUP BY s.route_id
)
SELECT
  r.id AS route_id,
  r.channel_type AS channel,
  CASE
    WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('thread', 'topic') THEN 'thread'
    WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('p2p', 'private', 'direct', 'dm') THEN 'private'
    ELSE 'group'
  END AS conversation_type,
  r.external_conversation_id AS conversation_id,
  COALESCE(r.external_thread_id, '') AS thread_id,
  COALESCE(
    NULLIF(TRIM(COALESCE(r.metadata->>'conversation_name', '')), ''),
    NULLIF(TRIM(COALESCE(r.metadata->>'conversation_handle', '')), ''),
    ''
  )::text AS conversation_name,
  rr.last_observed_at
FROM observed_routes rr
JOIN bot_channel_routes r ON r.id = rr.route_id
GROUP BY
  r.id,
  r.channel_type,
  r.conversation_type,
  r.external_conversation_id,
  r.external_thread_id,
  r.metadata,
  rr.last_observed_at
ORDER BY rr.last_observed_at DESC
`

type ListObservedConversationsByChannelIdentityParams struct {
	BotID             pgtype.UUID `json:"bot_id"`
	ChannelIdentityID pgtype.UUID `json:"channel_identity_id"`
}

type ListObservedConversationsByChannelIdentityRow struct {
	RouteID          pgtype.UUID        `json:"route_id"`
	Channel          string             `json:"channel"`
	ConversationType string             `json:"conversation_type"`
	ConversationID   string             `json:"conversation_id"`
	ThreadID         string             `json:"thread_id"`
	ConversationName string             `json:"conversation_name"`
	LastObservedAt   pgtype.Timestamptz `json:"last_observed_at"`
}

func (q *Queries) ListObservedConversationsByChannelIdentity(ctx context.Context, arg ListObservedConversationsByChannelIdentityParams) ([]ListObservedConversationsByChannelIdentityRow, error) {
	rows, err := q.db.Query(ctx, listObservedConversationsByChannelIdentity, arg.BotID, arg.ChannelIdentityID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListObservedConversationsByChannelIdentityRow
	for rows.Next() {
		var i ListObservedConversationsByChannelIdentityRow
		if err := rows.Scan(
			&i.RouteID,
			&i.Channel,
			&i.ConversationType,
			&i.ConversationID,
			&i.ThreadID,
			&i.ConversationName,
			&i.LastObservedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listObservedConversationsByChannelType = `-- name: ListObservedConversationsByChannelType :many
WITH observed_routes AS (
  SELECT
    s.route_id,
    MAX(m.created_at)::timestamptz AS last_observed_at
  FROM bot_history_messages m
  JOIN bot_sessions s ON s.id = m.session_id
  JOIN bot_channel_routes r ON r.id = s.route_id
  WHERE m.bot_id = $1
    AND LOWER(TRIM(r.channel_type)) = LOWER(TRIM($2))
    AND s.route_id IS NOT NULL
  GROUP BY s.route_id
)
SELECT
  r.id AS route_id,
  r.channel_type AS channel,
  CASE
    WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('thread', 'topic') THEN 'thread'
    WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('p2p', 'private', 'direct', 'dm') THEN 'private'
    ELSE 'group'
  END AS conversation_type,
  r.external_conversation_id AS conversation_id,
  COALESCE(r.external_thread_id, '') AS thread_id,
  COALESCE(
    NULLIF(TRIM(COALESCE(r.metadata->>'conversation_name', '')), ''),
    NULLIF(TRIM(COALESCE(r.metadata->>'conversation_handle', '')), ''),
    ''
  )::text AS conversation_name,
  rr.last_observed_at
FROM observed_routes rr
JOIN bot_channel_routes r ON r.id = rr.route_id
GROUP BY
  r.id,
  r.channel_type,
  r.conversation_type,
  r.external_conversation_id,
  r.external_thread_id,
  r.metadata,
  rr.last_observed_at
ORDER BY rr.last_observed_at DESC
`

type ListObservedConversationsByChannelTypeParams struct {
	BotID       pgtype.UUID `json:"bot_id"`
	ChannelType string      `json:"channel_type"`
}

type ListObservedConversationsByChannelTypeRow struct {
	RouteID          pgtype.UUID        `json:"route_id"`
	Channel          string             `json:"channel"`
	ConversationType string             `json:"conversation_type"`
	ConversationID   string             `json:"conversation_id"`
	ThreadID         string             `json:"thread_id"`
	ConversationName string             `json:"conversation_name"`
	LastObservedAt   pgtype.Timestamptz `json:"last_observed_at"`
}

// Routes on this platform type where the bot has seen at least one message (any sender).
func (q *Queries) ListObservedConversationsByChannelType(ctx context.Context, arg ListObservedConversationsByChannelTypeParams) ([]ListObservedConversationsByChannelTypeRow, error) {
	rows, err := q.db.Query(ctx, listObservedConversationsByChannelType, arg.BotID, arg.ChannelType)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListObservedConversationsByChannelTypeRow
	for rows.Next() {
		var i ListObservedConversationsByChannelTypeRow
		if err := rows.Scan(
			&i.RouteID,
			&i.Channel,
			&i.ConversationType,
			&i.ConversationID,
			&i.ThreadID,
			&i.ConversationName,
			&i.LastObservedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listUncompactedMessagesBySession = `-- name: ListUncompactedMessagesBySession :many
SELECT id, bot_id, session_id, role, content, usage, sender_channel_identity_id, compact_id, created_at
FROM bot_history_messages
WHERE session_id = $1
  AND compact_id IS NULL
ORDER BY created_at ASC
`

type ListUncompactedMessagesBySessionRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	Usage                   []byte             `json:"usage"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	CompactID               pgtype.UUID        `json:"compact_id"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
}

func (q *Queries) ListUncompactedMessagesBySession(ctx context.Context, sessionID pgtype.UUID) ([]ListUncompactedMessagesBySessionRow, error) {
	rows, err := q.db.Query(ctx, listUncompactedMessagesBySession, sessionID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListUncompactedMessagesBySessionRow
	for rows.Next() {
		var i ListUncompactedMessagesBySessionRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.Role,
			&i.Content,
			&i.Usage,
			&i.SenderChannelIdentityID,
			&i.CompactID,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const markMessagesCompacted = `-- name: MarkMessagesCompacted :exec
UPDATE bot_history_messages
SET compact_id = $1
WHERE id = ANY($2::uuid[])
`

type MarkMessagesCompactedParams struct {
	CompactID pgtype.UUID   `json:"compact_id"`
	Column2   []pgtype.UUID `json:"column_2"`
}

func (q *Queries) MarkMessagesCompacted(ctx context.Context, arg MarkMessagesCompactedParams) error {
	_, err := q.db.Exec(ctx, markMessagesCompacted, arg.CompactID, arg.Column2)
	return err
}

const searchMessages = `-- name: SearchMessages :many
SELECT
  m.id,
  m.bot_id,
  m.session_id,
  m.sender_channel_identity_id,
  m.role,
  m.content,
  m.created_at,
  ci.display_name AS sender_display_name,
  s.channel_type AS platform
FROM bot_history_messages m
LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id
LEFT JOIN bot_sessions s ON s.id = m.session_id
WHERE m.bot_id = $1
  AND ($2::uuid IS NULL OR m.session_id = $2::uuid)
  AND ($3::uuid IS NULL OR m.sender_channel_identity_id = $3::uuid)
  AND ($4::timestamptz IS NULL OR m.created_at >= $4::timestamptz)
  AND ($5::timestamptz IS NULL OR m.created_at <= $5::timestamptz)
  AND ($6::text IS NULL OR m.role = $6::text)
  AND ($7::text IS NULL OR (
    CASE
      WHEN jsonb_typeof(m.content->'content') = 'string'
        THEN m.content->>'content'
      WHEN jsonb_typeof(m.content->'content') = 'array'
        THEN (SELECT COALESCE(string_agg(elem->>'text', ' '), '')
              FROM jsonb_array_elements(m.content->'content') AS elem
              WHERE elem->>'type' = 'text')
      ELSE ''
    END
  ) ILIKE '%' || $7::text || '%')
ORDER BY m.created_at DESC
LIMIT $8
`

type SearchMessagesParams struct {
	BotID     pgtype.UUID        `json:"bot_id"`
	SessionID pgtype.UUID        `json:"session_id"`
	ContactID pgtype.UUID        `json:"contact_id"`
	StartTime pgtype.Timestamptz `json:"start_time"`
	EndTime   pgtype.Timestamptz `json:"end_time"`
	Role      pgtype.Text        `json:"role"`
	Keyword   pgtype.Text        `json:"keyword"`
	MaxCount  int32              `json:"max_count"`
}

type SearchMessagesRow struct {
	ID                      pgtype.UUID        `json:"id"`
	BotID                   pgtype.UUID        `json:"bot_id"`
	SessionID               pgtype.UUID        `json:"session_id"`
	SenderChannelIdentityID pgtype.UUID        `json:"sender_channel_identity_id"`
	Role                    string             `json:"role"`
	Content                 []byte             `json:"content"`
	CreatedAt               pgtype.Timestamptz `json:"created_at"`
	SenderDisplayName       pgtype.Text        `json:"sender_display_name"`
	Platform                pgtype.Text        `json:"platform"`
}

func (q *Queries) SearchMessages(ctx context.Context, arg SearchMessagesParams) ([]SearchMessagesRow, error) {
	rows, err := q.db.Query(ctx, searchMessages,
		arg.BotID,
		arg.SessionID,
		arg.ContactID,
		arg.StartTime,
		arg.EndTime,
		arg.Role,
		arg.Keyword,
		arg.MaxCount,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []SearchMessagesRow
	for rows.Next() {
		var i SearchMessagesRow
		if err := rows.Scan(
			&i.ID,
			&i.BotID,
			&i.SessionID,
			&i.SenderChannelIdentityID,
			&i.Role,
			&i.Content,
			&i.CreatedAt,
			&i.SenderDisplayName,
			&i.Platform,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}
