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

package dbgen

import (
	"context"
	"database/sql"
)

const createAPIToken = `-- name: CreateAPIToken :execresult
INSERT INTO api_tokens (user_id, token_hash, label, expires_at)
VALUES (?, ?, ?, ?)
`

type CreateAPITokenParams struct {
	UserID    int64   `json:"userId"`
	TokenHash string  `json:"tokenHash"`
	Label     string  `json:"label"`
	ExpiresAt *string `json:"expiresAt"`
}

func (q *Queries) CreateAPIToken(ctx context.Context, arg CreateAPITokenParams) (sql.Result, error) {
	return q.db.ExecContext(ctx, createAPIToken,
		arg.UserID,
		arg.TokenHash,
		arg.Label,
		arg.ExpiresAt,
	)
}

const getActiveAPIToken = `-- name: GetActiveAPIToken :one
SELECT id, user_id, token_hash, label, created_at, last_used_at, expires_at, revoked_at
FROM api_tokens
WHERE token_hash = ?
  AND revoked_at IS NULL
  AND (expires_at IS NULL OR strftime('%s', expires_at) > strftime('%s', 'now'))
`

// Auth-hot lookup: returns the token only if it is neither revoked nor expired,
// so a resolved row is always usable. Matches the sessions never-expiring
// convention (expires_at IS NULL).
func (q *Queries) GetActiveAPIToken(ctx context.Context, tokenHash string) (ApiToken, error) {
	row := q.db.QueryRowContext(ctx, getActiveAPIToken, tokenHash)
	var i ApiToken
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.TokenHash,
		&i.Label,
		&i.CreatedAt,
		&i.LastUsedAt,
		&i.ExpiresAt,
		&i.RevokedAt,
	)
	return i, err
}

const getOwnerUser = `-- name: GetOwnerUser :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 banned = 0
   OR (ban_expires IS NOT NULL
       AND replace(ban_expires, ' ', 'T') <= strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
ORDER BY (SELECT r.position FROM roles r WHERE r.id = users.role_id) DESC, id ASC
`

// The highest-privilege account (role with the greatest position), used as the
// default identity for `token create`. FROM is users-only (role position is a
// correlated subquery, not a join) so the row maps through userFromGen exactly
// like GetUserByID, so keep this SELECT list identical to GetUserByID's.
// A :one query already reads a single row via QueryRow, so no LIMIT is needed
// (and an explicit LIMIT 1 is mis-emitted by sqlc here). ORDER BY puts the
// highest-position role first, so that first row is the owner.
// Banned users are excluded: account deletion anonymises the row and sets
// banned = 1 permanently, so without this filter a self-deleted Owner keeps
// outranking every live admin and becomes the default identity for token
// creation forever -- minting tokens the auth layer then 403s on every use.
// The ban_expires arm mirrors auth.IsEffectivelyBanned (and db.notBannedClause)
// so a lapsed temporary ban stays eligible; the replace() normalises the space
// separator form of ban_expires to 'T' before comparing, because ' ' sorts
// below 'T' and a same-day space-form expiry would otherwise read as lapsed.
func (q *Queries) GetOwnerUser(ctx context.Context) (User, error) {
	row := q.db.QueryRowContext(ctx, getOwnerUser)
	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 listAPITokens = `-- name: ListAPITokens :many
SELECT t.id, t.user_id, COALESCE(u.username, '') AS username, t.label,
       t.created_at, t.last_used_at, t.expires_at, t.revoked_at
FROM api_tokens t
LEFT JOIN users u ON u.id = t.user_id
ORDER BY t.id DESC
LIMIT 200
`

type ListAPITokensRow struct {
	ID         int64   `json:"id"`
	UserID     int64   `json:"userId"`
	Username   string  `json:"username"`
	Label      string  `json:"label"`
	CreatedAt  string  `json:"createdAt"`
	LastUsedAt *string `json:"lastUsedAt"`
	ExpiresAt  *string `json:"expiresAt"`
	RevokedAt  *string `json:"revokedAt"`
}

// Admin/CLI listing. Never selects token_hash (unrecoverable; only the raw
// token shown at creation is usable).
func (q *Queries) ListAPITokens(ctx context.Context) ([]ListAPITokensRow, error) {
	rows, err := q.db.QueryContext(ctx, listAPITokens)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListAPITokensRow{}
	for rows.Next() {
		var i ListAPITokensRow
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.Username,
			&i.Label,
			&i.CreatedAt,
			&i.LastUsedAt,
			&i.ExpiresAt,
			&i.RevokedAt,
		); 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 revokeAPIToken = `-- name: RevokeAPIToken :execresult
UPDATE api_tokens SET revoked_at = datetime('now')
WHERE id = ? AND revoked_at IS NULL
`

func (q *Queries) RevokeAPIToken(ctx context.Context, id int64) (sql.Result, error) {
	return q.db.ExecContext(ctx, revokeAPIToken, id)
}

const revokeAPITokenByLabel = `-- name: RevokeAPITokenByLabel :execresult
UPDATE api_tokens SET revoked_at = datetime('now')
WHERE label = ? AND revoked_at IS NULL
`

func (q *Queries) RevokeAPITokenByLabel(ctx context.Context, label string) (sql.Result, error) {
	return q.db.ExecContext(ctx, revokeAPITokenByLabel, label)
}

const touchAPIToken = `-- name: TouchAPIToken :exec
UPDATE api_tokens SET last_used_at = datetime('now') WHERE token_hash = ?
`

func (q *Queries) TouchAPIToken(ctx context.Context, tokenHash string) error {
	_, err := q.db.ExecContext(ctx, touchAPIToken, tokenHash)
	return err
}
