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

package dbgen

import (
	"context"
	"database/sql"
)

const banUser = `-- name: BanUser :exec
UPDATE users SET banned = 1, ban_reason = ?, ban_expires = ? WHERE id = ?
`

type BanUserParams struct {
	BanReason  *string `json:"banReason"`
	BanExpires *string `json:"banExpires"`
	ID         int64   `json:"id"`
}

func (q *Queries) BanUser(ctx context.Context, arg BanUserParams) error {
	_, err := q.db.ExecContext(ctx, banUser, arg.BanReason, arg.BanExpires, arg.ID)
	return err
}

const countUsers = `-- name: CountUsers :one
SELECT COUNT(*) FROM users
`

func (q *Queries) CountUsers(ctx context.Context) (int64, error) {
	row := q.db.QueryRowContext(ctx, countUsers)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const countUsersWithoutTOTP = `-- name: CountUsersWithoutTOTP :one
SELECT COUNT(*) FROM users WHERE banned = 0 AND totp_secret IS NULL
`

func (q *Queries) CountUsersWithoutTOTP(ctx context.Context) (int64, error) {
	row := q.db.QueryRowContext(ctx, countUsersWithoutTOTP)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const createUser = `-- name: CreateUser :execresult
INSERT INTO users (username, password, role_id) VALUES (?, ?, ?)
`

type CreateUserParams struct {
	Username string `json:"username"`
	Password string `json:"password"`
	RoleID   int64  `json:"roleId"`
}

func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (sql.Result, error) {
	return q.db.ExecContext(ctx, createUser, arg.Username, arg.Password, arg.RoleID)
}

const getUserByID = `-- name: GetUserByID :one
SELECT id, username, password, avatar, role_id, totp_secret, status,
       created_at, last_seen, banned, ban_reason, ban_expires, identity_public_key,
       display_name, about, custom_status
FROM users WHERE id = ?
`

func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
	row := q.db.QueryRowContext(ctx, getUserByID, id)
	var i User
	err := row.Scan(
		&i.ID,
		&i.Username,
		&i.Password,
		&i.Avatar,
		&i.RoleID,
		&i.TotpSecret,
		&i.Status,
		&i.CreatedAt,
		&i.LastSeen,
		&i.Banned,
		&i.BanReason,
		&i.BanExpires,
		&i.IdentityPublicKey,
		&i.DisplayName,
		&i.About,
		&i.CustomStatus,
	)
	return i, err
}

const getUserByUsername = `-- name: GetUserByUsername :one
SELECT id, username, password, avatar, role_id, totp_secret, status,
       created_at, last_seen, banned, ban_reason, ban_expires, identity_public_key,
       display_name, about, custom_status
FROM users WHERE username = ? COLLATE NOCASE
`

func (q *Queries) GetUserByUsername(ctx context.Context, username string) (User, error) {
	row := q.db.QueryRowContext(ctx, getUserByUsername, username)
	var i User
	err := row.Scan(
		&i.ID,
		&i.Username,
		&i.Password,
		&i.Avatar,
		&i.RoleID,
		&i.TotpSecret,
		&i.Status,
		&i.CreatedAt,
		&i.LastSeen,
		&i.Banned,
		&i.BanReason,
		&i.BanExpires,
		&i.IdentityPublicKey,
		&i.DisplayName,
		&i.About,
		&i.CustomStatus,
	)
	return i, err
}

const listMembers = `-- name: ListMembers :many
SELECT u.id, u.username, u.avatar, u.status, LOWER(r.name), u.identity_public_key,
       u.display_name, u.custom_status
FROM users u
JOIN roles r ON u.role_id = r.id
WHERE (u.banned = 0 OR (u.ban_expires IS NOT NULL AND replace(u.ban_expires, ' ', 'T') <= strftime('%Y-%m-%dT%H:%M:%SZ', 'now')))
ORDER BY u.username ASC
`

type ListMembersRow struct {
	ID                int64   `json:"id"`
	Username          string  `json:"username"`
	Avatar            *string `json:"avatar"`
	Status            string  `json:"status"`
	Lower             string  `json:"lower"`
	IdentityPublicKey *string `json:"identityPublicKey"`
	DisplayName       *string `json:"displayName"`
	CustomStatus      *string `json:"customStatus"`
}

// The ready payload's member roster. docs/protocol.md documents members[] as
// "All registered users", so this must not silently truncate: the previous
// LIMIT 1000 dropped every member past the first thousand with no has_more
// signal, leaving those users unrenderable and unmentionable on the client
// with nothing to indicate the list was incomplete.
func (q *Queries) ListMembers(ctx context.Context) ([]ListMembersRow, error) {
	rows, err := q.db.QueryContext(ctx, listMembers)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListMembersRow{}
	for rows.Next() {
		var i ListMembersRow
		if err := rows.Scan(
			&i.ID,
			&i.Username,
			&i.Avatar,
			&i.Status,
			&i.Lower,
			&i.IdentityPublicKey,
			&i.DisplayName,
			&i.CustomStatus,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const markUserDisconnected = `-- name: MarkUserDisconnected :exec
UPDATE users
SET status = CASE WHEN status = 'online' THEN 'offline' ELSE status END,
    last_seen = datetime('now')
WHERE id = ?
`

// Disconnect bookkeeping. It clears only 'online', which is the one status
// that means "has a live session"; idle, dnd and invisible are choices the
// user made and are what the next connect reads instead of stamping online
// (db.ConnectStatus). A stale choice never renders as "present" because the
// read path treats a member with no live connection as offline regardless.
func (q *Queries) MarkUserDisconnected(ctx context.Context, id int64) error {
	_, err := q.db.ExecContext(ctx, markUserDisconnected, id)
	return err
}

const resetAllUserStatuses = `-- name: ResetAllUserStatuses :exec
UPDATE users SET status = 'offline' WHERE status = 'online'
`

// Startup reset: nothing is connected yet, so every 'online' is a leftover
// from the previous process. Chosen statuses survive for the same reason they
// survive a disconnect.
func (q *Queries) ResetAllUserStatuses(ctx context.Context) error {
	_, err := q.db.ExecContext(ctx, resetAllUserStatuses)
	return err
}

const unbanUser = `-- name: UnbanUser :exec
UPDATE users SET banned = 0, ban_reason = NULL, ban_expires = NULL WHERE id = ?
`

func (q *Queries) UnbanUser(ctx context.Context, id int64) error {
	_, err := q.db.ExecContext(ctx, unbanUser, id)
	return err
}

const updateUserIdentityKey = `-- name: UpdateUserIdentityKey :exec
UPDATE users SET identity_public_key = ? WHERE id = ?
`

type UpdateUserIdentityKeyParams struct {
	IdentityPublicKey *string `json:"identityPublicKey"`
	ID                int64   `json:"id"`
}

func (q *Queries) UpdateUserIdentityKey(ctx context.Context, arg UpdateUserIdentityKeyParams) error {
	_, err := q.db.ExecContext(ctx, updateUserIdentityKey, arg.IdentityPublicKey, arg.ID)
	return err
}

const updateUserStatus = `-- name: UpdateUserStatus :exec
UPDATE users SET status = ?, last_seen = datetime('now') WHERE id = ?
`

type UpdateUserStatusParams struct {
	Status string `json:"status"`
	ID     int64  `json:"id"`
}

func (q *Queries) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) error {
	_, err := q.db.ExecContext(ctx, updateUserStatus, arg.Status, arg.ID)
	return err
}

const updateUserTOTPSecret = `-- name: UpdateUserTOTPSecret :exec
UPDATE users SET totp_secret = ? WHERE id = ?
`

type UpdateUserTOTPSecretParams struct {
	TotpSecret *string `json:"totpSecret"`
	ID         int64   `json:"id"`
}

func (q *Queries) UpdateUserTOTPSecret(ctx context.Context, arg UpdateUserTOTPSecretParams) error {
	_, err := q.db.ExecContext(ctx, updateUserTOTPSecret, arg.TotpSecret, arg.ID)
	return err
}
