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

package sqlc

import (
	"context"
	"encoding/json"

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

const countUsers = `-- name: CountUsers :one
SELECT count(*) 
FROM users u
WHERE 
    ($1::boolean IS NULL OR u.is_deleted = $1::boolean)
    AND (
        $2::uuid[] IS NULL OR 
        EXISTS (
            SELECT 1 FROM user_roles ur2 
            WHERE ur2.user_id = u.id 
              AND ur2.role_id = ANY($2::uuid[])
        )
    )
    AND ($3::text IS NULL OR u.auth_provider = $3::text)
    AND ($4::timestamptz IS NULL OR u.created_at >= $4::timestamptz)
    AND ($5::timestamptz IS NULL OR u.created_at <= $5::timestamptz)
    AND (
        $6::text IS NULL OR 
        u.id::text ILIKE '%' || $6::text || '%' OR
        u.email ILIKE '%' || $6::text || '%' OR
        EXISTS (
            SELECT 1 FROM user_profiles p 
            WHERE p.user_id = u.id 
            AND (
                p.full_name ILIKE '%' || $6::text || '%' OR 
                p.phone ILIKE '%' || $6::text || '%'
            )
        )
    )
`

type CountUsersParams struct {
	IsDeleted    pgtype.Bool        `json:"is_deleted"`
	RoleIds      []pgtype.UUID      `json:"role_ids"`
	AuthProvider pgtype.Text        `json:"auth_provider"`
	CreatedFrom  pgtype.Timestamptz `json:"created_from"`
	CreatedTo    pgtype.Timestamptz `json:"created_to"`
	SearchText   pgtype.Text        `json:"search_text"`
}

func (q *Queries) CountUsers(ctx context.Context, arg CountUsersParams) (int64, error) {
	row := q.db.QueryRow(ctx, countUsers,
		arg.IsDeleted,
		arg.RoleIds,
		arg.AuthProvider,
		arg.CreatedFrom,
		arg.CreatedTo,
		arg.SearchText,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const createUserProfile = `-- name: CreateUserProfile :one
INSERT INTO user_profiles (
    user_id,
    display_name,
    avatar_url
) VALUES (
    $1, $2, $3
)
RETURNING user_id, display_name, full_name, avatar_url, bio, location, website, country_code, phone, created_at, updated_at
`

type CreateUserProfileParams struct {
	UserID      pgtype.UUID `json:"user_id"`
	DisplayName pgtype.Text `json:"display_name"`
	AvatarUrl   pgtype.Text `json:"avatar_url"`
}

func (q *Queries) CreateUserProfile(ctx context.Context, arg CreateUserProfileParams) (UserProfile, error) {
	row := q.db.QueryRow(ctx, createUserProfile, arg.UserID, arg.DisplayName, arg.AvatarUrl)
	var i UserProfile
	err := row.Scan(
		&i.UserID,
		&i.DisplayName,
		&i.FullName,
		&i.AvatarUrl,
		&i.Bio,
		&i.Location,
		&i.Website,
		&i.CountryCode,
		&i.Phone,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const deleteUser = `-- name: DeleteUser :exec
UPDATE users
SET
    is_deleted = true
WHERE id = $1
`

func (q *Queries) DeleteUser(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, deleteUser, id)
	return err
}

const getTokenVersion = `-- name: GetTokenVersion :one
SELECT token_version
FROM users
WHERE id = $1 AND is_deleted = false
`

func (q *Queries) GetTokenVersion(ctx context.Context, id pgtype.UUID) (int32, error) {
	row := q.db.QueryRow(ctx, getTokenVersion, id)
	var token_version int32
	err := row.Scan(&token_version)
	return token_version, err
}

const getUserByEmail = `-- name: GetUserByEmail :one
SELECT
    u.id,
    u.email,
    u.password_hash,
    u.token_version,
    u.auth_provider,
    u.google_id,
    u.is_deleted,
    u.created_at,
    u.updated_at,

    (
        SELECT json_build_object(
            'display_name', p.display_name,
            'full_name', p.full_name,
            'avatar_url', p.avatar_url,
            'bio', p.bio,
            'location', p.location,
            'website', p.website,
            'country_code', p.country_code,
            'phone', p.phone
        )
        FROM user_profiles p
        WHERE p.user_id = u.id
    ) AS profile,

    (
        SELECT COALESCE(
            json_agg(json_build_object('id', r.id, 'name', r.name)),
            '[]'
        )::json
        FROM user_roles ur
        JOIN roles r ON ur.role_id = r.id
        WHERE ur.user_id = u.id
    ) AS roles

FROM users u
WHERE u.email = $1 AND u.is_deleted = false
`

type GetUserByEmailRow struct {
	ID           pgtype.UUID        `json:"id"`
	Email        string             `json:"email"`
	PasswordHash pgtype.Text        `json:"password_hash"`
	TokenVersion int32              `json:"token_version"`
	AuthProvider string             `json:"auth_provider"`
	GoogleID     pgtype.Text        `json:"google_id"`
	IsDeleted    bool               `json:"is_deleted"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	Profile      json.RawMessage    `json:"profile"`
	Roles        []byte             `json:"roles"`
}

func (q *Queries) GetUserByEmail(ctx context.Context, email string) (GetUserByEmailRow, error) {
	row := q.db.QueryRow(ctx, getUserByEmail, email)
	var i GetUserByEmailRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.PasswordHash,
		&i.TokenVersion,
		&i.AuthProvider,
		&i.GoogleID,
		&i.IsDeleted,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.Profile,
		&i.Roles,
	)
	return i, err
}

const getUserByID = `-- name: GetUserByID :one
SELECT
    u.id,
    u.email,
    u.password_hash,
    u.token_version,
    u.refresh_token,
    u.auth_provider,
    u.google_id,
    u.is_deleted,
    u.created_at,
    u.updated_at,

    -- profile JSON
    (
        SELECT json_build_object(
            'display_name', p.display_name,
            'full_name', p.full_name,
            'avatar_url', p.avatar_url,
            'bio', p.bio,
            'location', p.location,
            'website', p.website,
            'country_code', p.country_code,
            'phone', p.phone
        )
        FROM user_profiles p
        WHERE p.user_id = u.id
    ) AS profile,

    -- roles JSON
    (
        SELECT COALESCE(
            json_agg(json_build_object('id', r.id, 'name', r.name)),
            '[]'
        )::json
        FROM user_roles ur
        JOIN roles r ON ur.role_id = r.id
        WHERE ur.user_id = u.id
    ) AS roles

FROM users u
WHERE u.id = $1 AND u.is_deleted = false
`

type GetUserByIDRow struct {
	ID           pgtype.UUID        `json:"id"`
	Email        string             `json:"email"`
	PasswordHash pgtype.Text        `json:"password_hash"`
	TokenVersion int32              `json:"token_version"`
	RefreshToken pgtype.Text        `json:"refresh_token"`
	AuthProvider string             `json:"auth_provider"`
	GoogleID     pgtype.Text        `json:"google_id"`
	IsDeleted    bool               `json:"is_deleted"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	Profile      json.RawMessage    `json:"profile"`
	Roles        []byte             `json:"roles"`
}

func (q *Queries) GetUserByID(ctx context.Context, id pgtype.UUID) (GetUserByIDRow, error) {
	row := q.db.QueryRow(ctx, getUserByID, id)
	var i GetUserByIDRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.PasswordHash,
		&i.TokenVersion,
		&i.RefreshToken,
		&i.AuthProvider,
		&i.GoogleID,
		&i.IsDeleted,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.Profile,
		&i.Roles,
	)
	return i, err
}

const getUserByIDWithoutDeleted = `-- name: GetUserByIDWithoutDeleted :one
SELECT
    u.id,
    u.email,
    u.password_hash,
    u.token_version,
    u.refresh_token,
    u.auth_provider,
    u.google_id,
    u.is_deleted,
    u.created_at,
    u.updated_at,

    -- profile JSON
    (
        SELECT json_build_object(
            'display_name', p.display_name,
            'full_name', p.full_name,
            'avatar_url', p.avatar_url,
            'bio', p.bio,
            'location', p.location,
            'website', p.website,
            'country_code', p.country_code,
            'phone', p.phone
        )
        FROM user_profiles p
        WHERE p.user_id = u.id
    ) AS profile,

    -- roles JSON
    (
        SELECT COALESCE(
            json_agg(json_build_object('id', r.id, 'name', r.name)),
            '[]'
        )::json
        FROM user_roles ur
        JOIN roles r ON ur.role_id = r.id
        WHERE ur.user_id = u.id
    ) AS roles

FROM users u
WHERE u.id = $1
`

type GetUserByIDWithoutDeletedRow struct {
	ID           pgtype.UUID        `json:"id"`
	Email        string             `json:"email"`
	PasswordHash pgtype.Text        `json:"password_hash"`
	TokenVersion int32              `json:"token_version"`
	RefreshToken pgtype.Text        `json:"refresh_token"`
	AuthProvider string             `json:"auth_provider"`
	GoogleID     pgtype.Text        `json:"google_id"`
	IsDeleted    bool               `json:"is_deleted"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	Profile      json.RawMessage    `json:"profile"`
	Roles        []byte             `json:"roles"`
}

func (q *Queries) GetUserByIDWithoutDeleted(ctx context.Context, id pgtype.UUID) (GetUserByIDWithoutDeletedRow, error) {
	row := q.db.QueryRow(ctx, getUserByIDWithoutDeleted, id)
	var i GetUserByIDWithoutDeletedRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.PasswordHash,
		&i.TokenVersion,
		&i.RefreshToken,
		&i.AuthProvider,
		&i.GoogleID,
		&i.IsDeleted,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.Profile,
		&i.Roles,
	)
	return i, err
}

const getUsersByIDs = `-- name: GetUsersByIDs :many
SELECT 
    u.id, 
    u.email, 
    u.password_hash, 
    u.token_version, 
    u.auth_provider,
    u.google_id,
    u.is_deleted, 
    u.created_at, 
    u.updated_at,
    (
        SELECT json_build_object(
            'display_name', p.display_name,
            'full_name', p.full_name,
            'avatar_url', p.avatar_url,
            'bio', p.bio,
            'location', p.location,
            'website', p.website,
            'country_code', p.country_code,
            'phone', p.phone
        )
        FROM user_profiles p
        WHERE p.user_id = u.id
    ) AS profile,
    (
        SELECT COALESCE(
            json_agg(json_build_object('id', r.id, 'name', r.name)),
            '[]'
        )::json
        FROM user_roles ur
        JOIN roles r ON ur.role_id = r.id
        WHERE ur.user_id = u.id
    ) AS roles
FROM users u
WHERE u.id = ANY($1::uuid[]) AND u.is_deleted = false
`

type GetUsersByIDsRow struct {
	ID           pgtype.UUID        `json:"id"`
	Email        string             `json:"email"`
	PasswordHash pgtype.Text        `json:"password_hash"`
	TokenVersion int32              `json:"token_version"`
	AuthProvider string             `json:"auth_provider"`
	GoogleID     pgtype.Text        `json:"google_id"`
	IsDeleted    bool               `json:"is_deleted"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	Profile      json.RawMessage    `json:"profile"`
	Roles        []byte             `json:"roles"`
}

func (q *Queries) GetUsersByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]GetUsersByIDsRow, error) {
	rows, err := q.db.Query(ctx, getUsersByIDs, dollar_1)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUsersByIDsRow{}
	for rows.Next() {
		var i GetUsersByIDsRow
		if err := rows.Scan(
			&i.ID,
			&i.Email,
			&i.PasswordHash,
			&i.TokenVersion,
			&i.AuthProvider,
			&i.GoogleID,
			&i.IsDeleted,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.Profile,
			&i.Roles,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const restoreUser = `-- name: RestoreUser :exec
UPDATE users
SET
    is_deleted = false
WHERE id = $1
`

func (q *Queries) RestoreUser(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, restoreUser, id)
	return err
}

const searchUsers = `-- name: SearchUsers :many
SELECT
    u.id,
    u.email,
    u.password_hash,
    u.token_version,
    u.google_id,
    u.auth_provider,
    u.refresh_token,
    u.is_deleted,
    u.created_at,
    u.updated_at,
    (
        SELECT json_build_object(
            'display_name', p.display_name,
            'full_name', p.full_name,
            'avatar_url', p.avatar_url,
            'bio', p.bio,
            'location', p.location,
            'website', p.website,
            'country_code', p.country_code,
            'phone', p.phone
        )
        FROM user_profiles p
        WHERE p.user_id = u.id
    ) AS profile,
    (
        SELECT COALESCE(
            json_agg(json_build_object('id', r.id, 'name', r.name)),
            '[]'
        )::json
        FROM user_roles ur
        JOIN roles r ON ur.role_id = r.id
        WHERE ur.user_id = u.id
    ) AS roles
FROM users u
WHERE 
    ($1::boolean IS NULL OR u.is_deleted = $1::boolean)
    AND (
        $2::uuid[] IS NULL OR 
        EXISTS (
            SELECT 1 FROM user_roles ur2 
            WHERE ur2.user_id = u.id 
              AND ur2.role_id = ANY($2::uuid[])
        )
    )
    AND ($3::text IS NULL OR u.auth_provider = $3::text)
    AND ($4::timestamptz IS NULL OR u.created_at >= $4::timestamptz)
    AND ($5::timestamptz IS NULL OR u.created_at <= $5::timestamptz)
    AND (
        $6::text IS NULL OR 
        u.id::text ILIKE '%' || $6::text || '%' OR
        u.email ILIKE '%' || $6::text || '%' OR
        EXISTS (
            SELECT 1 FROM user_profiles p 
            WHERE p.user_id = u.id 
            AND (
                p.full_name ILIKE '%' || $6::text || '%' OR 
                p.display_name ILIKE '%' || $6::text || '%' OR 
                p.phone ILIKE '%' || $6::text || '%'
            )
        )
    )
ORDER BY
    CASE WHEN $7 = 'id' AND $8 = 'asc' THEN u.id END ASC,
    CASE WHEN $7 = 'id' AND $8 = 'desc' THEN u.id END DESC,
    CASE WHEN $7 = 'created_at' AND $8 = 'asc' THEN u.created_at END ASC,
    CASE WHEN $7 = 'created_at' AND $8 = 'desc' THEN u.created_at END DESC,
    CASE WHEN $7 = 'updated_at' AND $8 = 'asc' THEN u.updated_at END ASC,
    CASE WHEN $7 = 'updated_at' AND $8 = 'desc' THEN u.updated_at END DESC,
    CASE WHEN $7 = 'email' AND $8 = 'asc' THEN u.email END ASC,
    CASE WHEN $7 = 'email' AND $8 = 'desc' THEN u.email END DESC,
    CASE WHEN $7 = 'is_deleted' AND $8 = 'asc' THEN u.is_deleted END ASC,
    CASE WHEN $7 = 'is_deleted' AND $8 = 'desc' THEN u.is_deleted END DESC,
    CASE WHEN $7 = 'auth_provider' AND $8 = 'asc' THEN u.auth_provider END ASC,
    CASE WHEN $7 = 'auth_provider' AND $8 = 'desc' THEN u.auth_provider END DESC,
    u.id ASC
LIMIT $10
OFFSET $9
`

type SearchUsersParams struct {
	IsDeleted    pgtype.Bool        `json:"is_deleted"`
	RoleIds      []pgtype.UUID      `json:"role_ids"`
	AuthProvider pgtype.Text        `json:"auth_provider"`
	CreatedFrom  pgtype.Timestamptz `json:"created_from"`
	CreatedTo    pgtype.Timestamptz `json:"created_to"`
	SearchText   pgtype.Text        `json:"search_text"`
	Sort         interface{}        `json:"sort"`
	Order        interface{}        `json:"order"`
	Offset       int32              `json:"offset"`
	Limit        int32              `json:"limit"`
}

type SearchUsersRow struct {
	ID           pgtype.UUID        `json:"id"`
	Email        string             `json:"email"`
	PasswordHash pgtype.Text        `json:"password_hash"`
	TokenVersion int32              `json:"token_version"`
	GoogleID     pgtype.Text        `json:"google_id"`
	AuthProvider string             `json:"auth_provider"`
	RefreshToken pgtype.Text        `json:"refresh_token"`
	IsDeleted    bool               `json:"is_deleted"`
	CreatedAt    pgtype.Timestamptz `json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `json:"updated_at"`
	Profile      json.RawMessage    `json:"profile"`
	Roles        []byte             `json:"roles"`
}

func (q *Queries) SearchUsers(ctx context.Context, arg SearchUsersParams) ([]SearchUsersRow, error) {
	rows, err := q.db.Query(ctx, searchUsers,
		arg.IsDeleted,
		arg.RoleIds,
		arg.AuthProvider,
		arg.CreatedFrom,
		arg.CreatedTo,
		arg.SearchText,
		arg.Sort,
		arg.Order,
		arg.Offset,
		arg.Limit,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SearchUsersRow{}
	for rows.Next() {
		var i SearchUsersRow
		if err := rows.Scan(
			&i.ID,
			&i.Email,
			&i.PasswordHash,
			&i.TokenVersion,
			&i.GoogleID,
			&i.AuthProvider,
			&i.RefreshToken,
			&i.IsDeleted,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.Profile,
			&i.Roles,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const updateTokenVersion = `-- name: UpdateTokenVersion :exec
UPDATE users
SET token_version = $2
WHERE id = $1 AND is_deleted = false
`

type UpdateTokenVersionParams struct {
	ID           pgtype.UUID `json:"id"`
	TokenVersion int32       `json:"token_version"`
}

func (q *Queries) UpdateTokenVersion(ctx context.Context, arg UpdateTokenVersionParams) error {
	_, err := q.db.Exec(ctx, updateTokenVersion, arg.ID, arg.TokenVersion)
	return err
}

const updateUserPassword = `-- name: UpdateUserPassword :exec
UPDATE users
SET
    password_hash = $2
WHERE id = $1
  AND is_deleted = false
`

type UpdateUserPasswordParams struct {
	ID           pgtype.UUID `json:"id"`
	PasswordHash pgtype.Text `json:"password_hash"`
}

func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error {
	_, err := q.db.Exec(ctx, updateUserPassword, arg.ID, arg.PasswordHash)
	return err
}

const updateUserProfile = `-- name: UpdateUserProfile :one
UPDATE user_profiles
SET
    display_name = COALESCE($1, display_name),
    full_name = COALESCE($2, full_name),
    avatar_url = COALESCE($3, avatar_url),
    bio = COALESCE($4, bio),
    location = COALESCE($5, location),
    website = COALESCE($6, website),
    country_code = COALESCE($7, country_code),
    phone = COALESCE($8, phone),
    updated_at = now()
WHERE user_id = $9
RETURNING user_id, display_name, full_name, avatar_url, bio, location, website, country_code, phone, created_at, updated_at
`

type UpdateUserProfileParams struct {
	DisplayName pgtype.Text `json:"display_name"`
	FullName    pgtype.Text `json:"full_name"`
	AvatarUrl   pgtype.Text `json:"avatar_url"`
	Bio         pgtype.Text `json:"bio"`
	Location    pgtype.Text `json:"location"`
	Website     pgtype.Text `json:"website"`
	CountryCode pgtype.Text `json:"country_code"`
	Phone       pgtype.Text `json:"phone"`
	UserID      pgtype.UUID `json:"user_id"`
}

func (q *Queries) UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) (UserProfile, error) {
	row := q.db.QueryRow(ctx, updateUserProfile,
		arg.DisplayName,
		arg.FullName,
		arg.AvatarUrl,
		arg.Bio,
		arg.Location,
		arg.Website,
		arg.CountryCode,
		arg.Phone,
		arg.UserID,
	)
	var i UserProfile
	err := row.Scan(
		&i.UserID,
		&i.DisplayName,
		&i.FullName,
		&i.AvatarUrl,
		&i.Bio,
		&i.Location,
		&i.Website,
		&i.CountryCode,
		&i.Phone,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const updateUserRefreshToken = `-- name: UpdateUserRefreshToken :exec
UPDATE users
SET
    refresh_token = $2
WHERE id = $1
  AND is_deleted = false
`

type UpdateUserRefreshTokenParams struct {
	ID           pgtype.UUID `json:"id"`
	RefreshToken pgtype.Text `json:"refresh_token"`
}

func (q *Queries) UpdateUserRefreshToken(ctx context.Context, arg UpdateUserRefreshTokenParams) error {
	_, err := q.db.Exec(ctx, updateUserRefreshToken, arg.ID, arg.RefreshToken)
	return err
}

const upsertUser = `-- name: UpsertUser :one
INSERT INTO users (
    email,
    password_hash,
    google_id,
    auth_provider
) VALUES (
    $1, $2, $3, $4
)
ON CONFLICT (email) 
DO UPDATE SET
    google_id = EXCLUDED.google_id,
    auth_provider = EXCLUDED.auth_provider
RETURNING id, email, password_hash, google_id, auth_provider, is_deleted, token_version, refresh_token, created_at, updated_at
`

type UpsertUserParams struct {
	Email        string      `json:"email"`
	PasswordHash pgtype.Text `json:"password_hash"`
	GoogleID     pgtype.Text `json:"google_id"`
	AuthProvider string      `json:"auth_provider"`
}

func (q *Queries) UpsertUser(ctx context.Context, arg UpsertUserParams) (User, error) {
	row := q.db.QueryRow(ctx, upsertUser,
		arg.Email,
		arg.PasswordHash,
		arg.GoogleID,
		arg.AuthProvider,
	)
	var i User
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.PasswordHash,
		&i.GoogleID,
		&i.AuthProvider,
		&i.IsDeleted,
		&i.TokenVersion,
		&i.RefreshToken,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}
