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

package sqlcgen

import (
	"context"
	"database/sql"
	"strings"
)

const deleteAlbum = `-- name: DeleteAlbum :exec
DELETE FROM albums WHERE id = ?
`

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

const deleteAllAlbums = `-- name: DeleteAllAlbums :exec
DELETE FROM albums
`

func (q *Queries) DeleteAllAlbums(ctx context.Context) error {
	_, err := q.db.ExecContext(ctx, deleteAllAlbums)
	return err
}

const getAlbum = `-- name: GetAlbum :one
SELECT id, name, artist_credit, artist_id, mbid, year, original_year, cover_art_id, pending_release_mbid FROM albums WHERE id = ? LIMIT 1
`

func (q *Queries) GetAlbum(ctx context.Context, id int64) (Album, error) {
	row := q.db.QueryRowContext(ctx, getAlbum, id)
	var i Album
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.ArtistCredit,
		&i.ArtistID,
		&i.Mbid,
		&i.Year,
		&i.OriginalYear,
		&i.CoverArtID,
		&i.PendingReleaseMbid,
	)
	return i, err
}

const getAlbumCompleteness = `-- name: GetAlbumCompleteness :one
SELECT
    -- Distinct (disc, track) pairs: this app detects duplicates, and
    -- counting two files of track 3 twice would report a short album as
    -- complete.  A file with no track number falls back to its own id,
    -- because three untagged files are three tracks, not one.
    CAST(COUNT(DISTINCT CAST(COALESCE(a.disc_number, 1) AS TEXT) || ':' ||
                        COALESCE(CAST(a.track_number AS TEXT), 'f' || a.id)
    ) AS INTEGER) AS owned,
    CAST(COALESCE((
        SELECT SUM(per_disc.total)
        FROM (
            SELECT MAX(b.total_tracks) AS total
            FROM audio_files b
            WHERE b.album_id = ?1 AND b.total_tracks IS NOT NULL
            GROUP BY COALESCE(b.disc_number, 1)
        ) per_disc
    ), 0) AS INTEGER) AS expected,
    CAST((
        SELECT COUNT(*) = 0 FROM audio_files c
        WHERE c.album_id = ?1 AND c.total_tracks IS NULL
    ) AS INTEGER) AS known
FROM audio_files a
WHERE a.album_id = ?1
`

type GetAlbumCompletenessRow struct {
	Owned    int64
	Expected int64
	Known    int64
}

// "Do I have all of this album", answered from the tags on disk.
//
// The expectation is a **sum over discs**, not one number: totals are
// declared per disc ("5/12" on disc 2 means 12 tracks on disc 2), so a
// multi-disc album's expectation is the sum of each disc's declared
// total.  A disc whose files declared nothing leaves the whole album
// unknowable rather than being covered by the discs that did -- which is
// what `known` reports.
//
// Owned counts DISTINCT track numbers: this app detects duplicates, and
// counting two files of track 3 twice would report a short album as
// complete.
func (q *Queries) GetAlbumCompleteness(ctx context.Context, albumID sql.NullInt64) (GetAlbumCompletenessRow, error) {
	row := q.db.QueryRowContext(ctx, getAlbumCompleteness, albumID)
	var i GetAlbumCompletenessRow
	err := row.Scan(&i.Owned, &i.Expected, &i.Known)
	return i, err
}

const getAlbums = `-- name: GetAlbums :many
SELECT
    al.id,
    al.name,
    COALESCE(al.original_year, al.year) AS year,
    COALESCE(al.year, 0) AS release_year,
    al.mbid,
    al.artist_credit AS artist_name,
    CAST(COALESCE(ar.mbid, '') AS TEXT) AS artist_mbid,
    COALESCE(ca.file_path, '') AS cover_art_path
FROM albums al
LEFT JOIN artists ar   ON ar.id = al.artist_id
LEFT JOIN cover_art ca ON ca.id = al.cover_art_id
WHERE EXISTS (
    SELECT 1 FROM audio_files af
    WHERE af.album_id = al.id
      AND af.library_id = COALESCE(NULLIF(CAST(?1 AS INTEGER), 0), af.library_id)
)
ORDER BY al.name
`

type GetAlbumsRow struct {
	ID           int64
	Name         string
	Year         sql.NullInt64
	ReleaseYear  int64
	Mbid         sql.NullString
	ArtistName   string
	ArtistMbid   string
	CoverArtPath string
}

func (q *Queries) GetAlbums(ctx context.Context, libraryID int64) ([]GetAlbumsRow, error) {
	rows, err := q.db.QueryContext(ctx, getAlbums, libraryID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetAlbumsRow
	for rows.Next() {
		var i GetAlbumsRow
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.Year,
			&i.ReleaseYear,
			&i.Mbid,
			&i.ArtistName,
			&i.ArtistMbid,
			&i.CoverArtPath,
		); 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 getAlbumsByArtistName = `-- name: GetAlbumsByArtistName :many
SELECT
    al.id,
    al.name,
    COALESCE(al.original_year, al.year) AS year,
    COALESCE(al.year, 0) AS release_year,
    al.mbid,
    al.artist_credit AS artist_name,
    CAST(COALESCE(ar.mbid, '') AS TEXT) AS artist_mbid,
    COALESCE(ca.file_path, '') AS cover_art_path
FROM albums al
LEFT JOIN artists ar   ON ar.id = al.artist_id
LEFT JOIN cover_art ca ON ca.id = al.cover_art_id
WHERE (al.artist_credit = ?1 OR ar.name = ?1)
  AND EXISTS (
      SELECT 1 FROM audio_files af
      WHERE af.album_id = al.id
        AND af.library_id = COALESCE(NULLIF(CAST(?2 AS INTEGER), 0), af.library_id)
  )
ORDER BY year, al.name
`

type GetAlbumsByArtistNameParams struct {
	Artist    string
	LibraryID int64
}

type GetAlbumsByArtistNameRow struct {
	ID           int64
	Name         string
	Year         sql.NullInt64
	ReleaseYear  int64
	Mbid         sql.NullString
	ArtistName   string
	ArtistMbid   string
	CoverArtPath string
}

func (q *Queries) GetAlbumsByArtistName(ctx context.Context, arg GetAlbumsByArtistNameParams) ([]GetAlbumsByArtistNameRow, error) {
	rows, err := q.db.QueryContext(ctx, getAlbumsByArtistName, arg.Artist, arg.LibraryID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetAlbumsByArtistNameRow
	for rows.Next() {
		var i GetAlbumsByArtistNameRow
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.Year,
			&i.ReleaseYear,
			&i.Mbid,
			&i.ArtistName,
			&i.ArtistMbid,
			&i.CoverArtPath,
		); 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 getAlbumsCompleteness = `-- name: GetAlbumsCompleteness :many
WITH per_disc AS (
    SELECT
        album_id AS album_id,
        COUNT(DISTINCT COALESCE(CAST(track_number AS TEXT), 'f' || id))
            AS owned_on_disc,
        MAX(total_tracks) AS disc_total,
        SUM(CASE WHEN total_tracks IS NULL THEN 1 ELSE 0 END)
            AS discs_without_a_total
    FROM audio_files
    WHERE album_id IN (/*SLICE:album_ids*/?)
    GROUP BY album_id, COALESCE(disc_number, 1)
)
SELECT
    CAST(album_id AS INTEGER) AS album_id,
    CAST(SUM(owned_on_disc) AS INTEGER) AS owned,
    CAST(COALESCE(SUM(disc_total), 0) AS INTEGER) AS expected,
    CAST(SUM(discs_without_a_total) = 0 AS INTEGER) AS known
FROM per_disc
GROUP BY album_id
`

type GetAlbumsCompletenessRow struct {
	AlbumID  int64
	Owned    int64
	Expected int64
	Known    int64
}

// The same question as GetAlbumCompleteness, asked of a screenful of
// albums at once.
//
// A card grid cannot afford one query per card, and the answer it wants
// is the one thing a badge cannot guess: an album held 9 tracks of 12
// must show the count, never a bare tick.  So this is one query for the
// whole grid, asked only of the cards that have a local album id.
//
// It is two grouping levels rather than the single-album form's
// correlated subqueries, because a correlated subquery in the FROM
// clause is not something SQLite will reliably do -- and because the
// slice may only be spelled once, or sqlc expands it twice with
// independently numbered placeholders.
//
// The per-disc level is where the meaning is, and it is the same
// meaning as the single-album query.  `owned` counts DISTINCT track
// numbers within a disc (this app detects duplicates, and counting two
// files of track 3 twice would report a short album as complete), with
// a file that declares no track number falling back to its own id
// because three untagged files are three tracks and not one.
// `expected` takes each disc's declared total and sums over discs,
// since a total is declared per disc and a release total written on
// every file of a two-disc album would double its expectation.  A disc
// whose files declared nothing contributes a NULL that SUM ignores,
// and `known` is what says the album is therefore unanswerable.
func (q *Queries) GetAlbumsCompleteness(ctx context.Context, albumIds []sql.NullInt64) ([]GetAlbumsCompletenessRow, error) {
	query := getAlbumsCompleteness
	var queryParams []interface{}
	if len(albumIds) > 0 {
		for _, v := range albumIds {
			queryParams = append(queryParams, v)
		}
		query = strings.Replace(query, "/*SLICE:album_ids*/?", strings.Repeat(",?", len(albumIds))[1:], 1)
	} else {
		query = strings.Replace(query, "/*SLICE:album_ids*/?", "NULL", 1)
	}
	rows, err := q.db.QueryContext(ctx, query, queryParams...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetAlbumsCompletenessRow
	for rows.Next() {
		var i GetAlbumsCompletenessRow
		if err := rows.Scan(
			&i.AlbumID,
			&i.Owned,
			&i.Expected,
			&i.Known,
		); 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 getAlbumsWithPendingReleaseMBID = `-- name: GetAlbumsWithPendingReleaseMBID :many
SELECT id, pending_release_mbid FROM albums
WHERE pending_release_mbid IS NOT NULL AND pending_release_mbid != ''
  AND (mbid IS NULL OR mbid = '')
LIMIT ?
`

type GetAlbumsWithPendingReleaseMBIDRow struct {
	ID                 int64
	PendingReleaseMbid sql.NullString
}

func (q *Queries) GetAlbumsWithPendingReleaseMBID(ctx context.Context, limit int64) ([]GetAlbumsWithPendingReleaseMBIDRow, error) {
	rows, err := q.db.QueryContext(ctx, getAlbumsWithPendingReleaseMBID, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetAlbumsWithPendingReleaseMBIDRow
	for rows.Next() {
		var i GetAlbumsWithPendingReleaseMBIDRow
		if err := rows.Scan(&i.ID, &i.PendingReleaseMbid); 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 getEmptyAlbumIDs = `-- name: GetEmptyAlbumIDs :many
SELECT id FROM albums al
WHERE NOT EXISTS (
    SELECT 1 FROM audio_files af WHERE af.album_id = al.id
)
`

// Albums with no file left behind them.  Under the old schema this was
// one of three orphan sweeps that had to run by hand and did not;
// audio_files is the only thing that can leave an album empty now, so
// this is the whole of it.
func (q *Queries) GetEmptyAlbumIDs(ctx context.Context) ([]int64, error) {
	rows, err := q.db.QueryContext(ctx, getEmptyAlbumIDs)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []int64
	for rows.Next() {
		var id int64
		if err := rows.Scan(&id); err != nil {
			return nil, err
		}
		items = append(items, id)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const resolveAlbumPendingReleaseMBID = `-- name: ResolveAlbumPendingReleaseMBID :exec
UPDATE albums
SET mbid = ?, pending_release_mbid = NULL
WHERE id = ? AND (mbid IS NULL OR mbid = '')
`

type ResolveAlbumPendingReleaseMBIDParams struct {
	Mbid sql.NullString
	ID   int64
}

// Clears the pending marker once the release-group MBID it stood in for
// has been resolved.  Guarded so a real MBID is never overwritten.
func (q *Queries) ResolveAlbumPendingReleaseMBID(ctx context.Context, arg ResolveAlbumPendingReleaseMBIDParams) error {
	_, err := q.db.ExecContext(ctx, resolveAlbumPendingReleaseMBID, arg.Mbid, arg.ID)
	return err
}

const setAlbumCoverArt = `-- name: SetAlbumCoverArt :exec
UPDATE albums SET cover_art_id = ? WHERE id = ?
`

type SetAlbumCoverArtParams struct {
	CoverArtID sql.NullInt64
	ID         int64
}

func (q *Queries) SetAlbumCoverArt(ctx context.Context, arg SetAlbumCoverArtParams) error {
	_, err := q.db.ExecContext(ctx, setAlbumCoverArt, arg.CoverArtID, arg.ID)
	return err
}

const setAlbumMBID = `-- name: SetAlbumMBID :exec
UPDATE albums SET mbid = ? WHERE id = ?
`

type SetAlbumMBIDParams struct {
	Mbid sql.NullString
	ID   int64
}

func (q *Queries) SetAlbumMBID(ctx context.Context, arg SetAlbumMBIDParams) error {
	_, err := q.db.ExecContext(ctx, setAlbumMBID, arg.Mbid, arg.ID)
	return err
}

const setAlbumOriginalYear = `-- name: SetAlbumOriginalYear :exec
UPDATE albums SET original_year = ? WHERE id = ?
`

type SetAlbumOriginalYearParams struct {
	OriginalYear sql.NullInt64
	ID           int64
}

func (q *Queries) SetAlbumOriginalYear(ctx context.Context, arg SetAlbumOriginalYearParams) error {
	_, err := q.db.ExecContext(ctx, setAlbumOriginalYear, arg.OriginalYear, arg.ID)
	return err
}

const setAlbumPendingReleaseMBID = `-- name: SetAlbumPendingReleaseMBID :exec
UPDATE albums SET pending_release_mbid = ? WHERE id = ?
`

type SetAlbumPendingReleaseMBIDParams struct {
	PendingReleaseMbid sql.NullString
	ID                 int64
}

func (q *Queries) SetAlbumPendingReleaseMBID(ctx context.Context, arg SetAlbumPendingReleaseMBIDParams) error {
	_, err := q.db.ExecContext(ctx, setAlbumPendingReleaseMBID, arg.PendingReleaseMbid, arg.ID)
	return err
}

const upsertAlbum = `-- name: UpsertAlbum :one

INSERT INTO albums (name, artist_credit, artist_id, year, cover_art_id)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(name, artist_credit) DO UPDATE SET
    artist_id    = COALESCE(excluded.artist_id, albums.artist_id),
    year         = COALESCE(excluded.year, albums.year),
    cover_art_id = COALESCE(excluded.cover_art_id, albums.cover_art_id)
RETURNING id, name, artist_credit, artist_id, mbid, year, original_year, cover_art_id, pending_release_mbid
`

type UpsertAlbumParams struct {
	Name         string
	ArtistCredit string
	ArtistID     sql.NullInt64
	Year         sql.NullInt64
	CoverArtID   sql.NullInt64
}

// Queries over albums (formerly release_groups).
//
// The two-copy pattern is gone here too: one query answers both the
// whole-library and the single-library case.  The `fallback_ac`
// subquery every album read used to carry -- "if the album has no album
// artist credit, borrow one from any of its recordings" -- is gone with
// it, because the album carries its own credit text now.
func (q *Queries) UpsertAlbum(ctx context.Context, arg UpsertAlbumParams) (Album, error) {
	row := q.db.QueryRowContext(ctx, upsertAlbum,
		arg.Name,
		arg.ArtistCredit,
		arg.ArtistID,
		arg.Year,
		arg.CoverArtID,
	)
	var i Album
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.ArtistCredit,
		&i.ArtistID,
		&i.Mbid,
		&i.Year,
		&i.OriginalYear,
		&i.CoverArtID,
		&i.PendingReleaseMbid,
	)
	return i, err
}
