// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.31.1
// source: similarity.sql

package dbq

import (
	"context"

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

const getArtistsByMBIDs = `-- name: GetArtistsByMBIDs :many
SELECT id, mbid FROM artists WHERE mbid = ANY($1::text[])
`

type GetArtistsByMBIDsRow struct {
	ID   pgtype.UUID
	Mbid *string
}

func (q *Queries) GetArtistsByMBIDs(ctx context.Context, dollar_1 []string) ([]GetArtistsByMBIDsRow, error) {
	rows, err := q.db.Query(ctx, getArtistsByMBIDs, dollar_1)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetArtistsByMBIDsRow
	for rows.Next() {
		var i GetArtistsByMBIDsRow
		if err := rows.Scan(&i.ID, &i.Mbid); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getTracksByMBIDs = `-- name: GetTracksByMBIDs :many
SELECT id, mbid FROM tracks WHERE mbid = ANY($1::text[])
`

type GetTracksByMBIDsRow struct {
	ID   pgtype.UUID
	Mbid *string
}

// Bulk in-library lookup: maps a slice of MBIDs back to local track IDs.
func (q *Queries) GetTracksByMBIDs(ctx context.Context, dollar_1 []string) ([]GetTracksByMBIDsRow, error) {
	rows, err := q.db.Query(ctx, getTracksByMBIDs, dollar_1)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetTracksByMBIDsRow
	for rows.Next() {
		var i GetTracksByMBIDsRow
		if err := rows.Scan(&i.ID, &i.Mbid); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listPlayedArtistsNeedingSimilarity = `-- name: ListPlayedArtistsNeedingSimilarity :many
SELECT DISTINCT ar.id, ar.mbid
FROM artists ar
JOIN tracks t ON t.artist_id = ar.id
JOIN play_events pe ON pe.track_id = t.id
WHERE ar.mbid IS NOT NULL
  AND NOT EXISTS (
      SELECT 1 FROM artist_similarity asim
      WHERE asim.artist_a_id = ar.id
        AND asim.source = 'listenbrainz'
        AND asim.fetched_at > now() - interval '7 days'
  )
ORDER BY ar.id
LIMIT $1
`

type ListPlayedArtistsNeedingSimilarityRow struct {
	ID   pgtype.UUID
	Mbid *string
}

func (q *Queries) ListPlayedArtistsNeedingSimilarity(ctx context.Context, limit int32) ([]ListPlayedArtistsNeedingSimilarityRow, error) {
	rows, err := q.db.Query(ctx, listPlayedArtistsNeedingSimilarity, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListPlayedArtistsNeedingSimilarityRow
	for rows.Next() {
		var i ListPlayedArtistsNeedingSimilarityRow
		if err := rows.Scan(&i.ID, &i.Mbid); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listPlayedTracksNeedingSimilarity = `-- name: ListPlayedTracksNeedingSimilarity :many
SELECT DISTINCT t.id, t.mbid
FROM tracks t
JOIN play_events pe ON pe.track_id = t.id
WHERE t.mbid IS NOT NULL
  AND NOT EXISTS (
      SELECT 1 FROM track_similarity ts
      WHERE ts.track_a_id = t.id
        AND ts.source = 'listenbrainz'
        AND ts.fetched_at > now() - interval '7 days'
  )
ORDER BY t.id
LIMIT $1
`

type ListPlayedTracksNeedingSimilarityRow struct {
	ID   pgtype.UUID
	Mbid *string
}

// Tracks with at least one play, an MBID, and no fresh listenbrainz row
// (no row at all, OR fetched_at older than 7 days). Used by the worker
// to find work each tick. Bounded by $1.
func (q *Queries) ListPlayedTracksNeedingSimilarity(ctx context.Context, limit int32) ([]ListPlayedTracksNeedingSimilarityRow, error) {
	rows, err := q.db.Query(ctx, listPlayedTracksNeedingSimilarity, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListPlayedTracksNeedingSimilarityRow
	for rows.Next() {
		var i ListPlayedTracksNeedingSimilarityRow
		if err := rows.Scan(&i.ID, &i.Mbid); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSimilarArtistsForArtist = `-- name: ListSimilarArtistsForArtist :many
SELECT artists.id, artists.name, artists.sort_name, artists.mbid, artists.created_at, artists.updated_at, artists.artist_thumb_path, artists.artist_fanart_path, artists.artist_art_source, artists.artist_art_sources_version,
       cov.id AS cover_album_id,
       cnt.album_count::bigint AS album_count
FROM (
    SELECT artist_b_id, max(score) AS sim_score
    FROM artist_similarity
    WHERE artist_a_id = $1
    GROUP BY artist_b_id
) s
JOIN artists ON artists.id = s.artist_b_id
LEFT JOIN LATERAL (
    SELECT id FROM albums
    WHERE artist_id = artists.id AND cover_art_path IS NOT NULL
    ORDER BY created_at DESC LIMIT 1
) cov ON true
LEFT JOIN LATERAL (
    SELECT count(*) AS album_count
    FROM albums WHERE artist_id = artists.id
) cnt ON true
ORDER BY s.sim_score DESC, artists.sort_name
LIMIT $2
`

type ListSimilarArtistsForArtistParams struct {
	SeedArtistID pgtype.UUID
	ResultLimit  int32
}

type ListSimilarArtistsForArtistRow struct {
	Artist       Artist
	CoverAlbumID pgtype.UUID
	AlbumCount   int64
}

// In-library artists similar to a seed artist, ranked by best similarity
// score across sources (deduped per candidate). cover_album_id + album_count
// mirror ListArtistsAlphaWithCovers so the strip renders identical cards.
func (q *Queries) ListSimilarArtistsForArtist(ctx context.Context, arg ListSimilarArtistsForArtistParams) ([]ListSimilarArtistsForArtistRow, error) {
	rows, err := q.db.Query(ctx, listSimilarArtistsForArtist, arg.SeedArtistID, arg.ResultLimit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSimilarArtistsForArtistRow
	for rows.Next() {
		var i ListSimilarArtistsForArtistRow
		if err := rows.Scan(
			&i.Artist.ID,
			&i.Artist.Name,
			&i.Artist.SortName,
			&i.Artist.Mbid,
			&i.Artist.CreatedAt,
			&i.Artist.UpdatedAt,
			&i.Artist.ArtistThumbPath,
			&i.Artist.ArtistFanartPath,
			&i.Artist.ArtistArtSource,
			&i.Artist.ArtistArtSourcesVersion,
			&i.CoverAlbumID,
			&i.AlbumCount,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const upsertArtistSimilarity = `-- name: UpsertArtistSimilarity :exec
INSERT INTO artist_similarity (artist_a_id, artist_b_id, score, source, fetched_at)
VALUES ($1, $2, $3, 'listenbrainz', now())
ON CONFLICT (artist_a_id, artist_b_id, source)
DO UPDATE SET score = EXCLUDED.score, fetched_at = EXCLUDED.fetched_at
`

type UpsertArtistSimilarityParams struct {
	ArtistAID pgtype.UUID
	ArtistBID pgtype.UUID
	Score     float64
}

func (q *Queries) UpsertArtistSimilarity(ctx context.Context, arg UpsertArtistSimilarityParams) error {
	_, err := q.db.Exec(ctx, upsertArtistSimilarity, arg.ArtistAID, arg.ArtistBID, arg.Score)
	return err
}

const upsertArtistSimilarityUnmatched = `-- name: UpsertArtistSimilarityUnmatched :exec
INSERT INTO artist_similarity_unmatched (
    seed_artist_id, candidate_mbid, candidate_name, score, source
) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (seed_artist_id, candidate_mbid, source) DO UPDATE SET
    candidate_name = EXCLUDED.candidate_name,
    score          = EXCLUDED.score,
    fetched_at     = now()
`

type UpsertArtistSimilarityUnmatchedParams struct {
	SeedArtistID  pgtype.UUID
	CandidateMbid string
	CandidateName string
	Score         float64
	Source        string
}

// Persists an out-of-library similar-artist MBID. Idempotent on
// (seed_artist_id, candidate_mbid, source) — re-fetches refresh the
// name/score and bump fetched_at.
func (q *Queries) UpsertArtistSimilarityUnmatched(ctx context.Context, arg UpsertArtistSimilarityUnmatchedParams) error {
	_, err := q.db.Exec(ctx, upsertArtistSimilarityUnmatched,
		arg.SeedArtistID,
		arg.CandidateMbid,
		arg.CandidateName,
		arg.Score,
		arg.Source,
	)
	return err
}

const upsertTrackSimilarity = `-- name: UpsertTrackSimilarity :exec
INSERT INTO track_similarity (track_a_id, track_b_id, score, source, fetched_at)
VALUES ($1, $2, $3, 'listenbrainz', now())
ON CONFLICT (track_a_id, track_b_id, source)
DO UPDATE SET score = EXCLUDED.score, fetched_at = EXCLUDED.fetched_at
`

type UpsertTrackSimilarityParams struct {
	TrackAID pgtype.UUID
	TrackBID pgtype.UUID
	Score    float64
}

func (q *Queries) UpsertTrackSimilarity(ctx context.Context, arg UpsertTrackSimilarityParams) error {
	_, err := q.db.Exec(ctx, upsertTrackSimilarity, arg.TrackAID, arg.TrackBID, arg.Score)
	return err
}
