// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.29.0
// source: tenants.sql

package sqlcv1

import (
	"context"

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

const controllerPartitionHeartbeat = `-- name: ControllerPartitionHeartbeat :one
UPDATE
    "ControllerPartition" p
SET
    "lastHeartbeat" = NOW()
WHERE
    p."id" = $1::text
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) ControllerPartitionHeartbeat(ctx context.Context, db DBTX, controllerpartitionid string) (*ControllerPartition, error) {
	row := db.QueryRow(ctx, controllerPartitionHeartbeat, controllerpartitionid)
	var i ControllerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const createControllerPartition = `-- name: CreateControllerPartition :one
INSERT INTO "ControllerPartition" ("id", "createdAt", "lastHeartbeat", "name")
VALUES (gen_random_uuid()::text, NOW(), NOW(), $1::text)
ON CONFLICT DO NOTHING
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) CreateControllerPartition(ctx context.Context, db DBTX, name pgtype.Text) (*ControllerPartition, error) {
	row := db.QueryRow(ctx, createControllerPartition, name)
	var i ControllerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const createSchedulerPartition = `-- name: CreateSchedulerPartition :one
INSERT INTO "SchedulerPartition" ("id", "createdAt", "lastHeartbeat", "name")
VALUES (gen_random_uuid()::text, NOW(), NOW(), $1::text)
ON CONFLICT DO NOTHING
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) CreateSchedulerPartition(ctx context.Context, db DBTX, name pgtype.Text) (*SchedulerPartition, error) {
	row := db.QueryRow(ctx, createSchedulerPartition, name)
	var i SchedulerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const createTenant = `-- name: CreateTenant :one
WITH active_controller_partitions AS (
    SELECT
        "id"
    FROM
        "ControllerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
)
INSERT INTO "Tenant" ("id", "name", "slug", "controllerPartitionId", "dataRetentionPeriod", "version", "onboardingData", "environment")
VALUES (
    $1::uuid,
    $2::text,
    $3::text,
    (
        SELECT
            "id"
        FROM
            active_controller_partitions
        ORDER BY
            random()
        LIMIT 1
    ),
    COALESCE($4::text, '720h'),
    COALESCE($5::"TenantMajorEngineVersion", 'V0'),
    $6::jsonb,
    $7::"TenantEnvironment"
)
RETURNING id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
`

type CreateTenantParams struct {
	ID                  uuid.UUID                    `json:"id"`
	Name                string                       `json:"name"`
	Slug                string                       `json:"slug"`
	DataRetentionPeriod pgtype.Text                  `json:"dataRetentionPeriod"`
	Version             NullTenantMajorEngineVersion `json:"version"`
	OnboardingData      []byte                       `json:"onboardingData"`
	Environment         NullTenantEnvironment        `json:"environment"`
}

func (q *Queries) CreateTenant(ctx context.Context, db DBTX, arg CreateTenantParams) (*Tenant, error) {
	row := db.QueryRow(ctx, createTenant,
		arg.ID,
		arg.Name,
		arg.Slug,
		arg.DataRetentionPeriod,
		arg.Version,
		arg.OnboardingData,
		arg.Environment,
	)
	var i Tenant
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.Version,
		&i.UiVersion,
		&i.Name,
		&i.Slug,
		&i.AnalyticsOptOut,
		&i.AlertMemberEmails,
		&i.ControllerPartitionId,
		&i.WorkerPartitionId,
		&i.DataRetentionPeriod,
		&i.SchedulerPartitionId,
		&i.CanUpgradeV1,
		&i.OnboardingData,
		&i.Environment,
	)
	return &i, err
}

const createTenantAlertGroup = `-- name: CreateTenantAlertGroup :one
INSERT INTO "TenantAlertEmailGroup" (
    "id",
    "tenantId",
    "emails"
) VALUES (
    gen_random_uuid(),
    $1::uuid,
    $2::text
) RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", emails
`

type CreateTenantAlertGroupParams struct {
	Tenantid uuid.UUID `json:"tenantid"`
	Emails   string    `json:"emails"`
}

func (q *Queries) CreateTenantAlertGroup(ctx context.Context, db DBTX, arg CreateTenantAlertGroupParams) (*TenantAlertEmailGroup, error) {
	row := db.QueryRow(ctx, createTenantAlertGroup, arg.Tenantid, arg.Emails)
	var i TenantAlertEmailGroup
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.Emails,
	)
	return &i, err
}

const createTenantAlertingSettings = `-- name: CreateTenantAlertingSettings :one
INSERT INTO "TenantAlertingSettings" ("id", "tenantId")
VALUES (gen_random_uuid(), $1::uuid)
RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "maxFrequency", "lastAlertedAt", "tickerId", "enableExpiringTokenAlerts", "enableWorkflowRunFailureAlerts", "enableTenantResourceLimitAlerts"
`

func (q *Queries) CreateTenantAlertingSettings(ctx context.Context, db DBTX, tenantid uuid.UUID) (*TenantAlertingSettings, error) {
	row := db.QueryRow(ctx, createTenantAlertingSettings, tenantid)
	var i TenantAlertingSettings
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.MaxFrequency,
		&i.LastAlertedAt,
		&i.TickerId,
		&i.EnableExpiringTokenAlerts,
		&i.EnableWorkflowRunFailureAlerts,
		&i.EnableTenantResourceLimitAlerts,
	)
	return &i, err
}

const createTenantMember = `-- name: CreateTenantMember :one
INSERT INTO "TenantMember" (
    "id",
    "tenantId",
    "userId",
    "role"
) VALUES (
    gen_random_uuid(),
    $1::uuid,
    $2::uuid,
    $3::"TenantMemberRole"
) ON CONFLICT ("tenantId", "userId") DO UPDATE SET
    "role" = $3::"TenantMemberRole"
RETURNING id, "createdAt", "updatedAt", "tenantId", "userId", role
`

type CreateTenantMemberParams struct {
	Tenantid uuid.UUID        `json:"tenantid"`
	Userid   uuid.UUID        `json:"userid"`
	Role     TenantMemberRole `json:"role"`
}

func (q *Queries) CreateTenantMember(ctx context.Context, db DBTX, arg CreateTenantMemberParams) (*TenantMember, error) {
	row := db.QueryRow(ctx, createTenantMember, arg.Tenantid, arg.Userid, arg.Role)
	var i TenantMember
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.TenantId,
		&i.UserId,
		&i.Role,
	)
	return &i, err
}

const createTenantWorkerPartition = `-- name: CreateTenantWorkerPartition :one
INSERT INTO "TenantWorkerPartition" ("id", "createdAt", "lastHeartbeat", "name")
VALUES (gen_random_uuid()::text, NOW(), NOW(), $1::text)
ON CONFLICT DO NOTHING
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) CreateTenantWorkerPartition(ctx context.Context, db DBTX, name pgtype.Text) (*TenantWorkerPartition, error) {
	row := db.QueryRow(ctx, createTenantWorkerPartition, name)
	var i TenantWorkerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const deleteControllerPartition = `-- name: DeleteControllerPartition :one
DELETE FROM "ControllerPartition"
WHERE "id" = $1::text
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) DeleteControllerPartition(ctx context.Context, db DBTX, id string) (*ControllerPartition, error) {
	row := db.QueryRow(ctx, deleteControllerPartition, id)
	var i ControllerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const deleteSchedulerPartition = `-- name: DeleteSchedulerPartition :one
DELETE FROM "SchedulerPartition"
WHERE "id" = $1::text
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) DeleteSchedulerPartition(ctx context.Context, db DBTX, id string) (*SchedulerPartition, error) {
	row := db.QueryRow(ctx, deleteSchedulerPartition, id)
	var i SchedulerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const deleteTenant = `-- name: DeleteTenant :one
UPDATE "Tenant"
SET "deletedAt" = NOW(),
    slug = slug || '_deleted_' || gen_random_uuid()
WHERE "id" = $1::uuid
RETURNING id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
`

func (q *Queries) DeleteTenant(ctx context.Context, db DBTX, id uuid.UUID) (*Tenant, error) {
	row := db.QueryRow(ctx, deleteTenant, id)
	var i Tenant
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.Version,
		&i.UiVersion,
		&i.Name,
		&i.Slug,
		&i.AnalyticsOptOut,
		&i.AlertMemberEmails,
		&i.ControllerPartitionId,
		&i.WorkerPartitionId,
		&i.DataRetentionPeriod,
		&i.SchedulerPartitionId,
		&i.CanUpgradeV1,
		&i.OnboardingData,
		&i.Environment,
	)
	return &i, err
}

const deleteTenantAlertGroup = `-- name: DeleteTenantAlertGroup :exec
DELETE FROM
    "TenantAlertEmailGroup"
WHERE
    "tenantId" = $1::uuid
    AND "id" = $2::uuid
`

type DeleteTenantAlertGroupParams struct {
	Tenantid uuid.UUID `json:"tenantid"`
	ID       uuid.UUID `json:"id"`
}

func (q *Queries) DeleteTenantAlertGroup(ctx context.Context, db DBTX, arg DeleteTenantAlertGroupParams) error {
	_, err := db.Exec(ctx, deleteTenantAlertGroup, arg.Tenantid, arg.ID)
	return err
}

const deleteTenantMember = `-- name: DeleteTenantMember :exec
DELETE FROM "TenantMember"
WHERE "id" = $1::uuid
`

func (q *Queries) DeleteTenantMember(ctx context.Context, db DBTX, id uuid.UUID) error {
	_, err := db.Exec(ctx, deleteTenantMember, id)
	return err
}

const deleteTenantWorkerPartition = `-- name: DeleteTenantWorkerPartition :one
DELETE FROM "TenantWorkerPartition"
WHERE "id" = $1::text
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) DeleteTenantWorkerPartition(ctx context.Context, db DBTX, id string) (*TenantWorkerPartition, error) {
	row := db.QueryRow(ctx, deleteTenantWorkerPartition, id)
	var i TenantWorkerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const getEmailGroups = `-- name: GetEmailGroups :many
SELECT
    id, "createdAt", "updatedAt", "deletedAt", "tenantId", emails
FROM
    "TenantAlertEmailGroup" as emailGroups
WHERE
    "tenantId" = $1::uuid
`

func (q *Queries) GetEmailGroups(ctx context.Context, db DBTX, tenantid uuid.UUID) ([]*TenantAlertEmailGroup, error) {
	rows, err := db.Query(ctx, getEmailGroups, tenantid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*TenantAlertEmailGroup
	for rows.Next() {
		var i TenantAlertEmailGroup
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.TenantId,
			&i.Emails,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getInternalTenantForController = `-- name: GetInternalTenantForController :one
SELECT
    id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
FROM
    "Tenant" as tenants
WHERE
    "controllerPartitionId" = $1::text
    AND "slug" = 'internal'
`

func (q *Queries) GetInternalTenantForController(ctx context.Context, db DBTX, controllerpartitionid string) (*Tenant, error) {
	row := db.QueryRow(ctx, getInternalTenantForController, controllerpartitionid)
	var i Tenant
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.Version,
		&i.UiVersion,
		&i.Name,
		&i.Slug,
		&i.AnalyticsOptOut,
		&i.AlertMemberEmails,
		&i.ControllerPartitionId,
		&i.WorkerPartitionId,
		&i.DataRetentionPeriod,
		&i.SchedulerPartitionId,
		&i.CanUpgradeV1,
		&i.OnboardingData,
		&i.Environment,
	)
	return &i, err
}

const getMemberEmailGroup = `-- name: GetMemberEmailGroup :many
SELECT u."email"
FROM "User" u
JOIN "TenantMember" tm ON u."id" = tm."userId"
WHERE u."emailVerified" = true
AND tm."tenantId" = $1::uuid
`

func (q *Queries) GetMemberEmailGroup(ctx context.Context, db DBTX, tenantid uuid.UUID) ([]string, error) {
	rows, err := db.Query(ctx, getMemberEmailGroup, tenantid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []string
	for rows.Next() {
		var email string
		if err := rows.Scan(&email); err != nil {
			return nil, err
		}
		items = append(items, email)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getSlackWebhooks = `-- name: GetSlackWebhooks :many
SELECT
    id, "createdAt", "updatedAt", "deletedAt", "tenantId", "teamId", "teamName", "channelId", "channelName", "webhookURL"
FROM
    "SlackAppWebhook" as slackWebhooks
WHERE
    "tenantId" = $1::uuid
`

func (q *Queries) GetSlackWebhooks(ctx context.Context, db DBTX, tenantid uuid.UUID) ([]*SlackAppWebhook, error) {
	rows, err := db.Query(ctx, getSlackWebhooks, tenantid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*SlackAppWebhook
	for rows.Next() {
		var i SlackAppWebhook
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.TenantId,
			&i.TeamId,
			&i.TeamName,
			&i.ChannelId,
			&i.ChannelName,
			&i.WebhookURL,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getTenantAlertGroupById = `-- name: GetTenantAlertGroupById :one
SELECT
    id, "createdAt", "updatedAt", "deletedAt", "tenantId", emails
FROM
    "TenantAlertEmailGroup"
WHERE
    "id" = $1::uuid
`

func (q *Queries) GetTenantAlertGroupById(ctx context.Context, db DBTX, id uuid.UUID) (*TenantAlertEmailGroup, error) {
	row := db.QueryRow(ctx, getTenantAlertGroupById, id)
	var i TenantAlertEmailGroup
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.Emails,
	)
	return &i, err
}

const getTenantAlertingSettings = `-- name: GetTenantAlertingSettings :one
SELECT
    id, "createdAt", "updatedAt", "deletedAt", "tenantId", "maxFrequency", "lastAlertedAt", "tickerId", "enableExpiringTokenAlerts", "enableWorkflowRunFailureAlerts", "enableTenantResourceLimitAlerts"
FROM
    "TenantAlertingSettings" as tenantAlertingSettings
WHERE
    "tenantId" = $1::uuid
`

func (q *Queries) GetTenantAlertingSettings(ctx context.Context, db DBTX, tenantid uuid.UUID) (*TenantAlertingSettings, error) {
	row := db.QueryRow(ctx, getTenantAlertingSettings, tenantid)
	var i TenantAlertingSettings
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.MaxFrequency,
		&i.LastAlertedAt,
		&i.TickerId,
		&i.EnableExpiringTokenAlerts,
		&i.EnableWorkflowRunFailureAlerts,
		&i.EnableTenantResourceLimitAlerts,
	)
	return &i, err
}

const getTenantByID = `-- name: GetTenantByID :one
SELECT
    id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
FROM
    "Tenant" as tenants
WHERE
    "id" = $1::uuid
    AND "deletedAt" IS NULL
`

func (q *Queries) GetTenantByID(ctx context.Context, db DBTX, id uuid.UUID) (*Tenant, error) {
	row := db.QueryRow(ctx, getTenantByID, id)
	var i Tenant
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.Version,
		&i.UiVersion,
		&i.Name,
		&i.Slug,
		&i.AnalyticsOptOut,
		&i.AlertMemberEmails,
		&i.ControllerPartitionId,
		&i.WorkerPartitionId,
		&i.DataRetentionPeriod,
		&i.SchedulerPartitionId,
		&i.CanUpgradeV1,
		&i.OnboardingData,
		&i.Environment,
	)
	return &i, err
}

const getTenantBySlug = `-- name: GetTenantBySlug :one
SELECT
    id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
FROM
    "Tenant" as tenants
WHERE
    "slug" = $1::text
    AND "deletedAt" IS NULL
`

func (q *Queries) GetTenantBySlug(ctx context.Context, db DBTX, slug string) (*Tenant, error) {
	row := db.QueryRow(ctx, getTenantBySlug, slug)
	var i Tenant
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.Version,
		&i.UiVersion,
		&i.Name,
		&i.Slug,
		&i.AnalyticsOptOut,
		&i.AlertMemberEmails,
		&i.ControllerPartitionId,
		&i.WorkerPartitionId,
		&i.DataRetentionPeriod,
		&i.SchedulerPartitionId,
		&i.CanUpgradeV1,
		&i.OnboardingData,
		&i.Environment,
	)
	return &i, err
}

const getTenantMemberByEmail = `-- name: GetTenantMemberByEmail :one
SELECT
    tm.id, tm."createdAt", tm."updatedAt", tm."tenantId", tm."userId", tm.role
FROM
    "TenantMember" tm
JOIN
    "User" u ON tm."userId" = u."id"
WHERE
    tm."tenantId" = $1::uuid
    AND u."email" = $2::text
`

type GetTenantMemberByEmailParams struct {
	Tenantid uuid.UUID `json:"tenantid"`
	Email    string    `json:"email"`
}

func (q *Queries) GetTenantMemberByEmail(ctx context.Context, db DBTX, arg GetTenantMemberByEmailParams) (*TenantMember, error) {
	row := db.QueryRow(ctx, getTenantMemberByEmail, arg.Tenantid, arg.Email)
	var i TenantMember
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.TenantId,
		&i.UserId,
		&i.Role,
	)
	return &i, err
}

const getTenantMemberByID = `-- name: GetTenantMemberByID :one
SELECT
    id, "createdAt", "updatedAt", "tenantId", "userId", role
FROM
    "TenantMember"
WHERE
    "id" = $1::uuid
`

func (q *Queries) GetTenantMemberByID(ctx context.Context, db DBTX, id uuid.UUID) (*TenantMember, error) {
	row := db.QueryRow(ctx, getTenantMemberByID, id)
	var i TenantMember
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.TenantId,
		&i.UserId,
		&i.Role,
	)
	return &i, err
}

const getTenantMemberByUserID = `-- name: GetTenantMemberByUserID :one
SELECT
    id, "createdAt", "updatedAt", "tenantId", "userId", role
FROM
    "TenantMember"
WHERE
    "tenantId" = $1::uuid
    AND "userId" = $2::uuid
`

type GetTenantMemberByUserIDParams struct {
	Tenantid uuid.UUID `json:"tenantid"`
	Userid   uuid.UUID `json:"userid"`
}

func (q *Queries) GetTenantMemberByUserID(ctx context.Context, db DBTX, arg GetTenantMemberByUserIDParams) (*TenantMember, error) {
	row := db.QueryRow(ctx, getTenantMemberByUserID, arg.Tenantid, arg.Userid)
	var i TenantMember
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.TenantId,
		&i.UserId,
		&i.Role,
	)
	return &i, err
}

const getTenantTotalQueueMetrics = `-- name: GetTenantTotalQueueMetrics :one
WITH valid_workflow_runs AS (
    SELECT
        runs."id", workflow."id" as "workflowId", workflow."name" as "workflowName"
    FROM
        "WorkflowRun" as runs
    LEFT JOIN
        "WorkflowVersion" as workflowVersion ON runs."workflowVersionId" = workflowVersion."id"
    LEFT JOIN
        "Workflow" as workflow ON workflowVersion."workflowId" = workflow."id"
    WHERE
        -- status of the workflow run must be pending, queued or running
        runs."status" IN ('PENDING', 'QUEUED', 'RUNNING') AND
        runs."tenantId" = $1 AND
        (
            $2::jsonb IS NULL OR
            runs."additionalMetadata" @> $2::jsonb
        ) AND
        (
            $3::uuid[] IS NULL OR
            workflow."id" = ANY($3::uuid[])
        )
)
SELECT
    -- count of step runs in a PENDING_ASSIGNMENT state
    COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING_ASSIGNMENT') as "pendingAssignmentCount",
    -- count of step runs in a PENDING state
    COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING') as "pendingCount",
    -- count of step runs in a RUNNING state
    COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'RUNNING') as "runningCount"
FROM
    valid_workflow_runs as runs
LEFT JOIN
    "JobRun" as jobRun ON runs."id" = jobRun."workflowRunId"
LEFT JOIN
    "StepRun" as stepRun ON jobRun."id" = stepRun."jobRunId"
`

type GetTenantTotalQueueMetricsParams struct {
	TenantId           uuid.UUID   `json:"tenantId"`
	AdditionalMetadata []byte      `json:"additionalMetadata"`
	WorkflowIds        []uuid.UUID `json:"workflowIds"`
}

type GetTenantTotalQueueMetricsRow struct {
	PendingAssignmentCount int64 `json:"pendingAssignmentCount"`
	PendingCount           int64 `json:"pendingCount"`
	RunningCount           int64 `json:"runningCount"`
}

func (q *Queries) GetTenantTotalQueueMetrics(ctx context.Context, db DBTX, arg GetTenantTotalQueueMetricsParams) (*GetTenantTotalQueueMetricsRow, error) {
	row := db.QueryRow(ctx, getTenantTotalQueueMetrics, arg.TenantId, arg.AdditionalMetadata, arg.WorkflowIds)
	var i GetTenantTotalQueueMetricsRow
	err := row.Scan(&i.PendingAssignmentCount, &i.PendingCount, &i.RunningCount)
	return &i, err
}

const getTenantUsageData = `-- name: GetTenantUsageData :one
WITH active_workers AS (
    SELECT
        workers."id"
    FROM
        "Worker" workers
    WHERE
        workers."tenantId" = $1::uuid
        AND workers."dispatcherId" IS NOT NULL
        AND workers."lastHeartbeatAt" > NOW() - INTERVAL '5 seconds'
        AND workers."isActive" = true
        AND workers."isPaused" = false
)
SELECT
    (SELECT COUNT(*) FROM active_workers) AS "workerCount",
    COALESCE((
        SELECT SUM(s.units)
        FROM v1_task_runtime_slot s
        WHERE s.tenant_id = $1::uuid
          AND s.worker_id IN (SELECT "id" FROM active_workers)
    ), 0)::bigint AS "usedWorkerSlotsCount",
    (SELECT COUNT(*) FROM "TenantMember" WHERE "tenantId" = $1::uuid) AS "tenantMembersCount"
`

type GetTenantUsageDataRow struct {
	WorkerCount          int64 `json:"workerCount"`
	UsedWorkerSlotsCount int64 `json:"usedWorkerSlotsCount"`
	TenantMembersCount   int64 `json:"tenantMembersCount"`
}

func (q *Queries) GetTenantUsageData(ctx context.Context, db DBTX, tenantid uuid.UUID) (*GetTenantUsageDataRow, error) {
	row := db.QueryRow(ctx, getTenantUsageData, tenantid)
	var i GetTenantUsageDataRow
	err := row.Scan(&i.WorkerCount, &i.UsedWorkerSlotsCount, &i.TenantMembersCount)
	return &i, err
}

const getTenantWorkflowQueueMetrics = `-- name: GetTenantWorkflowQueueMetrics :many
WITH valid_workflow_runs AS (
    SELECT
        runs."id", workflow."id" as "workflowId", workflow."name" as "workflowName"
    FROM
        "WorkflowRun" as runs
    LEFT JOIN
        "WorkflowVersion" as workflowVersion ON runs."workflowVersionId" = workflowVersion."id"
    LEFT JOIN
        "Workflow" as workflow ON workflowVersion."workflowId" = workflow."id"
    WHERE
        -- status of the workflow run must be pending, queued or running
        runs."status" IN ('PENDING', 'QUEUED', 'RUNNING') AND
        runs."tenantId" = $1 AND
        (
            $2::jsonb IS NULL OR
            runs."additionalMetadata" @> $2::jsonb
        ) AND
        (
            $3::uuid[] IS NULL OR
            workflow."id" = ANY($3::uuid[])
        )
)
SELECT
    runs."workflowId",
    -- count of step runs in a PENDING_ASSIGNMENT state
    COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING_ASSIGNMENT') as "pendingAssignmentCount",
    -- count of step runs in a PENDING state
    COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING') as "pendingCount",
    -- count of step runs in a RUNNING state
    COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'RUNNING') as "runningCount"
FROM
    valid_workflow_runs as runs
LEFT JOIN
    "JobRun" as jobRun ON runs."id" = jobRun."workflowRunId"
LEFT JOIN
    "StepRun" as stepRun ON jobRun."id" = stepRun."jobRunId"
GROUP BY
    runs."workflowId"
`

type GetTenantWorkflowQueueMetricsParams struct {
	TenantId           uuid.UUID   `json:"tenantId"`
	AdditionalMetadata []byte      `json:"additionalMetadata"`
	WorkflowIds        []uuid.UUID `json:"workflowIds"`
}

type GetTenantWorkflowQueueMetricsRow struct {
	WorkflowId             *uuid.UUID `json:"workflowId"`
	PendingAssignmentCount int64      `json:"pendingAssignmentCount"`
	PendingCount           int64      `json:"pendingCount"`
	RunningCount           int64      `json:"runningCount"`
}

func (q *Queries) GetTenantWorkflowQueueMetrics(ctx context.Context, db DBTX, arg GetTenantWorkflowQueueMetricsParams) ([]*GetTenantWorkflowQueueMetricsRow, error) {
	rows, err := db.Query(ctx, getTenantWorkflowQueueMetrics, arg.TenantId, arg.AdditionalMetadata, arg.WorkflowIds)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*GetTenantWorkflowQueueMetricsRow
	for rows.Next() {
		var i GetTenantWorkflowQueueMetricsRow
		if err := rows.Scan(
			&i.WorkflowId,
			&i.PendingAssignmentCount,
			&i.PendingCount,
			&i.RunningCount,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTenantAlertGroups = `-- name: ListTenantAlertGroups :many
SELECT
    id, "createdAt", "updatedAt", "deletedAt", "tenantId", emails
FROM
    "TenantAlertEmailGroup"
WHERE
    "tenantId" = $1::uuid
`

func (q *Queries) ListTenantAlertGroups(ctx context.Context, db DBTX, tenantid uuid.UUID) ([]*TenantAlertEmailGroup, error) {
	rows, err := db.Query(ctx, listTenantAlertGroups, tenantid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*TenantAlertEmailGroup
	for rows.Next() {
		var i TenantAlertEmailGroup
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.TenantId,
			&i.Emails,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTenantMembers = `-- name: ListTenantMembers :many
SELECT
    id, "createdAt", "updatedAt", "tenantId", "userId", role
FROM
    "TenantMember"
WHERE
    "tenantId" = $1::uuid
`

func (q *Queries) ListTenantMembers(ctx context.Context, db DBTX, tenantid uuid.UUID) ([]*TenantMember, error) {
	rows, err := db.Query(ctx, listTenantMembers, tenantid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*TenantMember
	for rows.Next() {
		var i TenantMember
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.TenantId,
			&i.UserId,
			&i.Role,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTenants = `-- name: ListTenants :many
SELECT
    id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
FROM
    "Tenant" as tenants
WHERE
    "deletedAt" IS NULL
`

func (q *Queries) ListTenants(ctx context.Context, db DBTX) ([]*Tenant, error) {
	rows, err := db.Query(ctx, listTenants)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*Tenant
	for rows.Next() {
		var i Tenant
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.Version,
			&i.UiVersion,
			&i.Name,
			&i.Slug,
			&i.AnalyticsOptOut,
			&i.AlertMemberEmails,
			&i.ControllerPartitionId,
			&i.WorkerPartitionId,
			&i.DataRetentionPeriod,
			&i.SchedulerPartitionId,
			&i.CanUpgradeV1,
			&i.OnboardingData,
			&i.Environment,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTenantsByControllerPartitionId = `-- name: ListTenantsByControllerPartitionId :many
SELECT "id"
FROM "Tenant"
WHERE
    "controllerPartitionId" = $1::text
    AND "version" = 'V1'::"TenantMajorEngineVersion"
    AND "deletedAt" IS NULL
`

func (q *Queries) ListTenantsByControllerPartitionId(ctx context.Context, db DBTX, controllerpartitionid string) ([]uuid.UUID, error) {
	rows, err := db.Query(ctx, listTenantsByControllerPartitionId, controllerpartitionid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []uuid.UUID
	for rows.Next() {
		var id uuid.UUID
		if err := rows.Scan(&id); err != nil {
			return nil, err
		}
		items = append(items, id)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTenantsBySchedulerPartitionId = `-- name: ListTenantsBySchedulerPartitionId :many
SELECT
    id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
FROM
    "Tenant" as tenants
WHERE
    "schedulerPartitionId" = $1::text
    AND "version" = 'V1'::"TenantMajorEngineVersion"
    AND "deletedAt" IS NULL
`

func (q *Queries) ListTenantsBySchedulerPartitionId(ctx context.Context, db DBTX, schedulerpartitionid string) ([]*Tenant, error) {
	rows, err := db.Query(ctx, listTenantsBySchedulerPartitionId, schedulerpartitionid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*Tenant
	for rows.Next() {
		var i Tenant
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.Version,
			&i.UiVersion,
			&i.Name,
			&i.Slug,
			&i.AnalyticsOptOut,
			&i.AlertMemberEmails,
			&i.ControllerPartitionId,
			&i.WorkerPartitionId,
			&i.DataRetentionPeriod,
			&i.SchedulerPartitionId,
			&i.CanUpgradeV1,
			&i.OnboardingData,
			&i.Environment,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTenantsByTenantWorkerPartitionId = `-- name: ListTenantsByTenantWorkerPartitionId :many
SELECT
    id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
FROM
    "Tenant" as tenants
WHERE
    "workerPartitionId" = $1::text
    AND "version" = 'V1'::"TenantMajorEngineVersion"
    AND "deletedAt" IS NULL
`

func (q *Queries) ListTenantsByTenantWorkerPartitionId(ctx context.Context, db DBTX, workerpartitionid string) ([]*Tenant, error) {
	rows, err := db.Query(ctx, listTenantsByTenantWorkerPartitionId, workerpartitionid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*Tenant
	for rows.Next() {
		var i Tenant
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.Version,
			&i.UiVersion,
			&i.Name,
			&i.Slug,
			&i.AnalyticsOptOut,
			&i.AlertMemberEmails,
			&i.ControllerPartitionId,
			&i.WorkerPartitionId,
			&i.DataRetentionPeriod,
			&i.SchedulerPartitionId,
			&i.CanUpgradeV1,
			&i.OnboardingData,
			&i.Environment,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const populateTenantMembers = `-- name: PopulateTenantMembers :many
SELECT
    tm.id, tm."createdAt", tm."updatedAt", tm."tenantId", tm."userId", tm.role,
    u."email",
    u."name",
    t."id" as "tenantId",
    t."createdAt" as "tenantCreatedAt",
    t."updatedAt" as "tenantUpdatedAt",
    t."name" as "tenantName",
    t."slug" as "tenantSlug",
    t."alertMemberEmails" as "alertMemberEmails",
    t."analyticsOptOut" as "analyticsOptOut",
    t."version" as "tenantVersion",
    t."environment" as "tenantEnvironment"
FROM
    "TenantMember" tm
JOIN
    "User" u ON tm."userId" = u."id"
JOIN
    "Tenant" t ON tm."tenantId" = t."id"
WHERE
    tm."id" = ANY($1::uuid[])
`

type PopulateTenantMembersRow struct {
	ID                uuid.UUID                `json:"id"`
	CreatedAt         pgtype.Timestamp         `json:"createdAt"`
	UpdatedAt         pgtype.Timestamp         `json:"updatedAt"`
	TenantId          uuid.UUID                `json:"tenantId"`
	UserId            uuid.UUID                `json:"userId"`
	Role              TenantMemberRole         `json:"role"`
	Email             string                   `json:"email"`
	Name              pgtype.Text              `json:"name"`
	TenantId_2        uuid.UUID                `json:"tenantId_2"`
	TenantCreatedAt   pgtype.Timestamp         `json:"tenantCreatedAt"`
	TenantUpdatedAt   pgtype.Timestamp         `json:"tenantUpdatedAt"`
	TenantName        string                   `json:"tenantName"`
	TenantSlug        string                   `json:"tenantSlug"`
	AlertMemberEmails bool                     `json:"alertMemberEmails"`
	AnalyticsOptOut   bool                     `json:"analyticsOptOut"`
	TenantVersion     TenantMajorEngineVersion `json:"tenantVersion"`
	TenantEnvironment NullTenantEnvironment    `json:"tenantEnvironment"`
}

func (q *Queries) PopulateTenantMembers(ctx context.Context, db DBTX, ids []uuid.UUID) ([]*PopulateTenantMembersRow, error) {
	rows, err := db.Query(ctx, populateTenantMembers, ids)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*PopulateTenantMembersRow
	for rows.Next() {
		var i PopulateTenantMembersRow
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.TenantId,
			&i.UserId,
			&i.Role,
			&i.Email,
			&i.Name,
			&i.TenantId_2,
			&i.TenantCreatedAt,
			&i.TenantUpdatedAt,
			&i.TenantName,
			&i.TenantSlug,
			&i.AlertMemberEmails,
			&i.AnalyticsOptOut,
			&i.TenantVersion,
			&i.TenantEnvironment,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const rebalanceAllControllerPartitions = `-- name: RebalanceAllControllerPartitions :exec
WITH active_partitions AS (
    SELECT
        "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "ControllerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
),
tenants_to_update AS (
    SELECT
        tenants."id" AS "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "Tenant" AS tenants
    -- For the controller partition, we DO use the internal tenant as well
)
UPDATE
    "Tenant" AS tenants
SET
    "controllerPartitionId" = partitions."id"
FROM
    tenants_to_update,
    active_partitions AS partitions
WHERE
    tenants."id" = tenants_to_update."id" AND
    partitions.row_number = (tenants_to_update.row_number - 1) % (SELECT COUNT(*) FROM active_partitions) + 1
`

func (q *Queries) RebalanceAllControllerPartitions(ctx context.Context, db DBTX) error {
	_, err := db.Exec(ctx, rebalanceAllControllerPartitions)
	return err
}

const rebalanceAllSchedulerPartitions = `-- name: RebalanceAllSchedulerPartitions :exec
WITH active_partitions AS (
    SELECT
        "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "SchedulerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
),
tenants_to_update AS (
    SELECT
        tenants."id" AS "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "Tenant" AS tenants
    WHERE
        tenants."slug" != 'internal'
)
UPDATE
    "Tenant" AS tenants
SET
    "schedulerPartitionId" = partitions."id"
FROM
    tenants_to_update,
    active_partitions AS partitions
WHERE
    tenants."id" = tenants_to_update."id" AND
    partitions.row_number = (tenants_to_update.row_number - 1) % (SELECT COUNT(*) FROM active_partitions) + 1
`

func (q *Queries) RebalanceAllSchedulerPartitions(ctx context.Context, db DBTX) error {
	_, err := db.Exec(ctx, rebalanceAllSchedulerPartitions)
	return err
}

const rebalanceAllTenantWorkerPartitions = `-- name: RebalanceAllTenantWorkerPartitions :exec
WITH active_partitions AS (
    SELECT
        "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "TenantWorkerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
),
tenants_to_update AS (
    SELECT
        tenants."id" AS "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "Tenant" AS tenants
    WHERE
        tenants."slug" != 'internal'
)
UPDATE
    "Tenant" AS tenants
SET
    "workerPartitionId" = partitions."id"
FROM
    tenants_to_update,
    active_partitions AS partitions
WHERE
    tenants."id" = tenants_to_update."id" AND
    partitions.row_number = (tenants_to_update.row_number - 1) % (SELECT COUNT(*) FROM active_partitions) + 1
`

func (q *Queries) RebalanceAllTenantWorkerPartitions(ctx context.Context, db DBTX) error {
	_, err := db.Exec(ctx, rebalanceAllTenantWorkerPartitions)
	return err
}

const rebalanceInactiveControllerPartitions = `-- name: RebalanceInactiveControllerPartitions :exec
WITH active_partitions AS (
    SELECT
        "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "ControllerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
), inactive_partitions AS (
    SELECT
        "id"
    FROM
        "ControllerPartition"
    WHERE
        "lastHeartbeat" <= NOW() - INTERVAL '1 minute'
), tenants_to_update AS (
    SELECT
        tenants."id" AS "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "Tenant" AS tenants
    WHERE
        "controllerPartitionId" IS NULL OR
        "controllerPartitionId" IN (SELECT "id" FROM inactive_partitions)
), update_tenants AS (
    UPDATE "Tenant" AS tenants
    SET "controllerPartitionId" = partitions."id"
    FROM
        tenants_to_update,
        active_partitions AS partitions
    WHERE
    tenants."id" = tenants_to_update."id" AND
    partitions.row_number = (tenants_to_update.row_number - 1) % (SELECT COUNT(*) FROM active_partitions) + 1
)
DELETE FROM "ControllerPartition"
WHERE "id" IN (SELECT "id" FROM inactive_partitions)
`

func (q *Queries) RebalanceInactiveControllerPartitions(ctx context.Context, db DBTX) error {
	_, err := db.Exec(ctx, rebalanceInactiveControllerPartitions)
	return err
}

const rebalanceInactiveSchedulerPartitions = `-- name: RebalanceInactiveSchedulerPartitions :exec
WITH active_partitions AS (
    SELECT
        "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "SchedulerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
), inactive_partitions AS (
    SELECT
        "id"
    FROM
        "SchedulerPartition"
    WHERE
        "lastHeartbeat" <= NOW() - INTERVAL '1 minute'
), tenants_to_update AS (
    SELECT
        tenants."id" AS "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "Tenant" AS tenants
    WHERE
        tenants."slug" != 'internal' AND
        (
            "schedulerPartitionId" IS NULL OR
            "schedulerPartitionId" IN (SELECT "id" FROM inactive_partitions)
        )
), update_tenants AS (
    UPDATE "Tenant" AS tenants
    SET "schedulerPartitionId" = partitions."id"
    FROM
        tenants_to_update,
        active_partitions AS partitions
    WHERE
    tenants."id" = tenants_to_update."id" AND
    partitions.row_number = (tenants_to_update.row_number - 1) % (SELECT COUNT(*) FROM active_partitions) + 1
)
DELETE FROM "SchedulerPartition"
WHERE "id" IN (SELECT "id" FROM inactive_partitions)
`

func (q *Queries) RebalanceInactiveSchedulerPartitions(ctx context.Context, db DBTX) error {
	_, err := db.Exec(ctx, rebalanceInactiveSchedulerPartitions)
	return err
}

const rebalanceInactiveTenantWorkerPartitions = `-- name: RebalanceInactiveTenantWorkerPartitions :exec
WITH active_partitions AS (
    SELECT
        "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "TenantWorkerPartition"
    WHERE
        "lastHeartbeat" > NOW() - INTERVAL '1 minute'
), inactive_partitions AS (
    SELECT
        "id"
    FROM
        "TenantWorkerPartition"
    WHERE
        "lastHeartbeat" <= NOW() - INTERVAL '1 minute'
), tenants_to_update AS (
    SELECT
        tenants."id" AS "id",
        ROW_NUMBER() OVER () AS row_number
    FROM
        "Tenant" AS tenants
    WHERE
        tenants."slug" != 'internal' AND
        (
            "workerPartitionId" IS NULL OR
            "workerPartitionId" IN (SELECT "id" FROM inactive_partitions)
        )
), update_tenants AS (
    UPDATE "Tenant" AS tenants
    SET "workerPartitionId" = partitions."id"
    FROM
        tenants_to_update,
        active_partitions AS partitions
    WHERE
    tenants."id" = tenants_to_update."id" AND
    partitions.row_number = (tenants_to_update.row_number - 1) % (SELECT COUNT(*) FROM active_partitions) + 1
)
DELETE FROM "TenantWorkerPartition"
WHERE "id" IN (SELECT "id" FROM inactive_partitions)
`

func (q *Queries) RebalanceInactiveTenantWorkerPartitions(ctx context.Context, db DBTX) error {
	_, err := db.Exec(ctx, rebalanceInactiveTenantWorkerPartitions)
	return err
}

const schedulerPartitionHeartbeat = `-- name: SchedulerPartitionHeartbeat :one
UPDATE
    "SchedulerPartition" p
SET
    "lastHeartbeat" = NOW()
WHERE
    p."id" = $1::text
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) SchedulerPartitionHeartbeat(ctx context.Context, db DBTX, schedulerpartitionid string) (*SchedulerPartition, error) {
	row := db.QueryRow(ctx, schedulerPartitionHeartbeat, schedulerpartitionid)
	var i SchedulerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}

const updateTenant = `-- name: UpdateTenant :one
UPDATE
    "Tenant"
SET
    "name" = COALESCE($1::text, "name"),
    "analyticsOptOut" = COALESCE($2::boolean, "analyticsOptOut"),
    "alertMemberEmails" = COALESCE($3::boolean, "alertMemberEmails"),
    "version" = COALESCE($4::"TenantMajorEngineVersion", "version")
WHERE
    "id" = $5::uuid
RETURNING id, "createdAt", "updatedAt", "deletedAt", version, "uiVersion", name, slug, "analyticsOptOut", "alertMemberEmails", "controllerPartitionId", "workerPartitionId", "dataRetentionPeriod", "schedulerPartitionId", "canUpgradeV1", "onboardingData", environment
`

type UpdateTenantParams struct {
	Name              pgtype.Text                  `json:"name"`
	AnalyticsOptOut   pgtype.Bool                  `json:"analyticsOptOut"`
	AlertMemberEmails pgtype.Bool                  `json:"alertMemberEmails"`
	Version           NullTenantMajorEngineVersion `json:"version"`
	ID                uuid.UUID                    `json:"id"`
}

func (q *Queries) UpdateTenant(ctx context.Context, db DBTX, arg UpdateTenantParams) (*Tenant, error) {
	row := db.QueryRow(ctx, updateTenant,
		arg.Name,
		arg.AnalyticsOptOut,
		arg.AlertMemberEmails,
		arg.Version,
		arg.ID,
	)
	var i Tenant
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.Version,
		&i.UiVersion,
		&i.Name,
		&i.Slug,
		&i.AnalyticsOptOut,
		&i.AlertMemberEmails,
		&i.ControllerPartitionId,
		&i.WorkerPartitionId,
		&i.DataRetentionPeriod,
		&i.SchedulerPartitionId,
		&i.CanUpgradeV1,
		&i.OnboardingData,
		&i.Environment,
	)
	return &i, err
}

const updateTenantAlertGroup = `-- name: UpdateTenantAlertGroup :one
UPDATE "TenantAlertEmailGroup"
SET "emails" = $1::text
WHERE "id" = $2::uuid
RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", emails
`

type UpdateTenantAlertGroupParams struct {
	Emails string    `json:"emails"`
	ID     uuid.UUID `json:"id"`
}

func (q *Queries) UpdateTenantAlertGroup(ctx context.Context, db DBTX, arg UpdateTenantAlertGroupParams) (*TenantAlertEmailGroup, error) {
	row := db.QueryRow(ctx, updateTenantAlertGroup, arg.Emails, arg.ID)
	var i TenantAlertEmailGroup
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.Emails,
	)
	return &i, err
}

const updateTenantAlertingSettings = `-- name: UpdateTenantAlertingSettings :one
UPDATE
    "TenantAlertingSettings" as tenantAlertingSettings
SET
    "lastAlertedAt" = COALESCE($1::timestamp, "lastAlertedAt")
WHERE
    "tenantId" = $2::uuid
RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "maxFrequency", "lastAlertedAt", "tickerId", "enableExpiringTokenAlerts", "enableWorkflowRunFailureAlerts", "enableTenantResourceLimitAlerts"
`

type UpdateTenantAlertingSettingsParams struct {
	LastAlertedAt pgtype.Timestamp `json:"lastAlertedAt"`
	TenantId      uuid.UUID        `json:"tenantId"`
}

func (q *Queries) UpdateTenantAlertingSettings(ctx context.Context, db DBTX, arg UpdateTenantAlertingSettingsParams) (*TenantAlertingSettings, error) {
	row := db.QueryRow(ctx, updateTenantAlertingSettings, arg.LastAlertedAt, arg.TenantId)
	var i TenantAlertingSettings
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.MaxFrequency,
		&i.LastAlertedAt,
		&i.TickerId,
		&i.EnableExpiringTokenAlerts,
		&i.EnableWorkflowRunFailureAlerts,
		&i.EnableTenantResourceLimitAlerts,
	)
	return &i, err
}

const updateTenantMember = `-- name: UpdateTenantMember :one
UPDATE "TenantMember"
SET
    "role" = COALESCE($1::"TenantMemberRole", "role")
WHERE "id" = $2::uuid
RETURNING id, "createdAt", "updatedAt", "tenantId", "userId", role
`

type UpdateTenantMemberParams struct {
	Role NullTenantMemberRole `json:"role"`
	ID   uuid.UUID            `json:"id"`
}

func (q *Queries) UpdateTenantMember(ctx context.Context, db DBTX, arg UpdateTenantMemberParams) (*TenantMember, error) {
	row := db.QueryRow(ctx, updateTenantMember, arg.Role, arg.ID)
	var i TenantMember
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.TenantId,
		&i.UserId,
		&i.Role,
	)
	return &i, err
}

const upsertTenantAlertingSettings = `-- name: UpsertTenantAlertingSettings :one
INSERT INTO "TenantAlertingSettings" (
    "id",
    "tenantId",
    "maxFrequency",
    "enableExpiringTokenAlerts",
    "enableWorkflowRunFailureAlerts",
    "enableTenantResourceLimitAlerts"
) VALUES (
    gen_random_uuid(),
    $1::uuid,
    COALESCE($2::text, '1h'),
    COALESCE($3::boolean, TRUE),
    COALESCE($4::boolean, FALSE),
    COALESCE($5::boolean, TRUE)
) ON CONFLICT ("tenantId") DO UPDATE SET
    "maxFrequency" = COALESCE($2::text, "TenantAlertingSettings"."maxFrequency"),
    "enableExpiringTokenAlerts" = COALESCE($3::boolean, "TenantAlertingSettings"."enableExpiringTokenAlerts"),
    "enableWorkflowRunFailureAlerts" = COALESCE($4::boolean, "TenantAlertingSettings"."enableWorkflowRunFailureAlerts"),
    "enableTenantResourceLimitAlerts" = COALESCE($5::boolean, "TenantAlertingSettings"."enableTenantResourceLimitAlerts")
RETURNING id, "createdAt", "updatedAt", "deletedAt", "tenantId", "maxFrequency", "lastAlertedAt", "tickerId", "enableExpiringTokenAlerts", "enableWorkflowRunFailureAlerts", "enableTenantResourceLimitAlerts"
`

type UpsertTenantAlertingSettingsParams struct {
	Tenantid                        uuid.UUID   `json:"tenantid"`
	MaxFrequency                    pgtype.Text `json:"maxFrequency"`
	EnableExpiringTokenAlerts       pgtype.Bool `json:"enableExpiringTokenAlerts"`
	EnableWorkflowRunFailureAlerts  pgtype.Bool `json:"enableWorkflowRunFailureAlerts"`
	EnableTenantResourceLimitAlerts pgtype.Bool `json:"enableTenantResourceLimitAlerts"`
}

func (q *Queries) UpsertTenantAlertingSettings(ctx context.Context, db DBTX, arg UpsertTenantAlertingSettingsParams) (*TenantAlertingSettings, error) {
	row := db.QueryRow(ctx, upsertTenantAlertingSettings,
		arg.Tenantid,
		arg.MaxFrequency,
		arg.EnableExpiringTokenAlerts,
		arg.EnableWorkflowRunFailureAlerts,
		arg.EnableTenantResourceLimitAlerts,
	)
	var i TenantAlertingSettings
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeletedAt,
		&i.TenantId,
		&i.MaxFrequency,
		&i.LastAlertedAt,
		&i.TickerId,
		&i.EnableExpiringTokenAlerts,
		&i.EnableWorkflowRunFailureAlerts,
		&i.EnableTenantResourceLimitAlerts,
	)
	return &i, err
}

const workerPartitionHeartbeat = `-- name: WorkerPartitionHeartbeat :one
UPDATE
    "TenantWorkerPartition" p
SET
    "lastHeartbeat" = NOW()
WHERE
    p."id" = $1::text
RETURNING id, "createdAt", "updatedAt", "lastHeartbeat", name
`

func (q *Queries) WorkerPartitionHeartbeat(ctx context.Context, db DBTX, workerpartitionid string) (*TenantWorkerPartition, error) {
	row := db.QueryRow(ctx, workerPartitionHeartbeat, workerpartitionid)
	var i TenantWorkerPartition
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeat,
		&i.Name,
	)
	return &i, err
}
