// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.27.0
// source: projects.sql

package sqlcdb

import (
	"context"
	"database/sql"

	"github.com/google/uuid"
)

const countProjectsByUser = `-- name: CountProjectsByUser :one
SELECT COUNT(*)::bigint AS total
FROM projects p
WHERE
    (p.owner_id = $1 OR EXISTS (
        SELECT 1
        FROM project_members pm
        WHERE pm.project_id = p.id AND pm.user_id = $1
    ))
    AND (
        $2::text IS NULL
        OR p.name ILIKE ('%' || $2::text || '%')
        OR COALESCE(p.description, '') ILIKE ('%' || $2::text || '%')
    )
`

type CountProjectsByUserParams struct {
	UserID uuid.UUID      `json:"user_id"`
	Search sql.NullString `json:"search"`
}

func (q *Queries) CountProjectsByUser(ctx context.Context, arg CountProjectsByUserParams) (int64, error) {
	row := q.db.QueryRowContext(ctx, countProjectsByUser, arg.UserID, arg.Search)
	var total int64
	err := row.Scan(&total)
	return total, err
}

const createProject = `-- name: CreateProject :one
INSERT INTO projects (name, description, owner_id)
VALUES ($1, $2, $3)
RETURNING id, name, description, owner_id, created_at, updated_at
`

type CreateProjectParams struct {
	Name        string         `json:"name"`
	Description sql.NullString `json:"description"`
	OwnerID     uuid.UUID      `json:"owner_id"`
}

func (q *Queries) CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error) {
	row := q.db.QueryRowContext(ctx, createProject, arg.Name, arg.Description, arg.OwnerID)
	var i Project
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.OwnerID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const deleteProjectByID = `-- name: DeleteProjectByID :execrows
DELETE FROM projects
WHERE id = $1
`

func (q *Queries) DeleteProjectByID(ctx context.Context, projectID uuid.UUID) (int64, error) {
	result, err := q.db.ExecContext(ctx, deleteProjectByID, projectID)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}

const getProjectByIDForUser = `-- name: GetProjectByIDForUser :one
SELECT p.id, p.name, p.description, p.owner_id, p.created_at, p.updated_at
FROM projects p
WHERE p.id = $1
  AND (
      p.owner_id = $2
      OR EXISTS (
          SELECT 1
          FROM project_members pm
          WHERE pm.project_id = p.id AND pm.user_id = $2
      )
  )
`

type GetProjectByIDForUserParams struct {
	ProjectID uuid.UUID `json:"project_id"`
	UserID    uuid.UUID `json:"user_id"`
}

func (q *Queries) GetProjectByIDForUser(ctx context.Context, arg GetProjectByIDForUserParams) (Project, error) {
	row := q.db.QueryRowContext(ctx, getProjectByIDForUser, arg.ProjectID, arg.UserID)
	var i Project
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.OwnerID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const getProjectOwnerByID = `-- name: GetProjectOwnerByID :one
SELECT owner_id
FROM projects
WHERE id = $1
`

func (q *Queries) GetProjectOwnerByID(ctx context.Context, projectID uuid.UUID) (uuid.UUID, error) {
	row := q.db.QueryRowContext(ctx, getProjectOwnerByID, projectID)
	var owner_id uuid.UUID
	err := row.Scan(&owner_id)
	return owner_id, err
}

const getProjectRoleForUser = `-- name: GetProjectRoleForUser :one
SELECT (CASE
    WHEN p.owner_id = $1 THEN 'owner'
    ELSE COALESCE(pm.role, '')
END)::text AS role
FROM projects p
LEFT JOIN project_members pm ON p.id = pm.project_id AND pm.user_id = $1
WHERE p.id = $2
`

type GetProjectRoleForUserParams struct {
	UserID    uuid.UUID `json:"user_id"`
	ProjectID uuid.UUID `json:"project_id"`
}

func (q *Queries) GetProjectRoleForUser(ctx context.Context, arg GetProjectRoleForUserParams) (string, error) {
	row := q.db.QueryRowContext(ctx, getProjectRoleForUser, arg.UserID, arg.ProjectID)
	var role string
	err := row.Scan(&role)
	return role, err
}

const insertProjectEnvironment = `-- name: InsertProjectEnvironment :exec
INSERT INTO environments (name, project_id)
VALUES ($1, $2)
`

type InsertProjectEnvironmentParams struct {
	Name      string    `json:"name"`
	ProjectID uuid.UUID `json:"project_id"`
}

func (q *Queries) InsertProjectEnvironment(ctx context.Context, arg InsertProjectEnvironmentParams) error {
	_, err := q.db.ExecContext(ctx, insertProjectEnvironment, arg.Name, arg.ProjectID)
	return err
}

const listProjectsWithStatsByUser = `-- name: ListProjectsWithStatsByUser :many
SELECT
    p.id,
    p.name,
    p.description,
    p.owner_id,
    p.created_at,
    p.updated_at,
    COUNT(DISTINCT s.id)::bigint AS service_count,
    COUNT(DISTINCT d.id)::bigint AS deployment_count,
    COUNT(DISTINCT CASE WHEN s.status = 'running' THEN s.id END)::bigint AS running_services,
    (
        SELECT d2.created_at
        FROM deployments d2
        JOIN services s2 ON s2.id = d2.service_id
        WHERE s2.project_id = p.id
        ORDER BY d2.created_at DESC
        LIMIT 1
    ) AS last_deployment
FROM projects p
LEFT JOIN services s ON s.project_id = p.id
LEFT JOIN deployments d ON d.service_id = s.id
WHERE
    (p.owner_id = $1 OR EXISTS (
        SELECT 1
        FROM project_members pm
        WHERE pm.project_id = p.id AND pm.user_id = $1
    ))
    AND (
        $2::text IS NULL
        OR p.name ILIKE ('%' || $2::text || '%')
        OR COALESCE(p.description, '') ILIKE ('%' || $2::text || '%')
    )
GROUP BY p.id, p.name, p.description, p.owner_id, p.created_at, p.updated_at
ORDER BY p.updated_at DESC
LIMIT $4 OFFSET $3
`

type ListProjectsWithStatsByUserParams struct {
	UserID      uuid.UUID      `json:"user_id"`
	Search      sql.NullString `json:"search"`
	OffsetCount int32          `json:"offset_count"`
	LimitCount  int32          `json:"limit_count"`
}

type ListProjectsWithStatsByUserRow struct {
	ID              uuid.UUID      `json:"id"`
	Name            string         `json:"name"`
	Description     sql.NullString `json:"description"`
	OwnerID         uuid.UUID      `json:"owner_id"`
	CreatedAt       sql.NullTime   `json:"created_at"`
	UpdatedAt       sql.NullTime   `json:"updated_at"`
	ServiceCount    int64          `json:"service_count"`
	DeploymentCount int64          `json:"deployment_count"`
	RunningServices int64          `json:"running_services"`
	LastDeployment  sql.NullTime   `json:"last_deployment"`
}

func (q *Queries) ListProjectsWithStatsByUser(ctx context.Context, arg ListProjectsWithStatsByUserParams) ([]ListProjectsWithStatsByUserRow, error) {
	rows, err := q.db.QueryContext(ctx, listProjectsWithStatsByUser,
		arg.UserID,
		arg.Search,
		arg.OffsetCount,
		arg.LimitCount,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListProjectsWithStatsByUserRow{}
	for rows.Next() {
		var i ListProjectsWithStatsByUserRow
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.Description,
			&i.OwnerID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.ServiceCount,
			&i.DeploymentCount,
			&i.RunningServices,
			&i.LastDeployment,
		); 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 updateProjectByID = `-- name: UpdateProjectByID :execrows
UPDATE projects
SET
    name = COALESCE($1, name),
    description = COALESCE($2, description),
    updated_at = NOW()
WHERE id = $3
`

type UpdateProjectByIDParams struct {
	Name        sql.NullString `json:"name"`
	Description sql.NullString `json:"description"`
	ProjectID   uuid.UUID      `json:"project_id"`
}

func (q *Queries) UpdateProjectByID(ctx context.Context, arg UpdateProjectByIDParams) (int64, error) {
	result, err := q.db.ExecContext(ctx, updateProjectByID, arg.Name, arg.Description, arg.ProjectID)
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}
