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

package dbq

import (
	"context"

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

const deleteTrackTags = `-- name: DeleteTrackTags :exec
DELETE FROM track_tags WHERE track_id = $1
`

// Clear a track's cached tags before rewriting (atomic replace by the caller).
func (q *Queries) DeleteTrackTags(ctx context.Context, trackID pgtype.UUID) error {
	_, err := q.db.Exec(ctx, deleteTrackTags, trackID)
	return err
}

const insertTrackTag = `-- name: InsertTrackTag :exec
INSERT INTO track_tags (track_id, tag, weight)
VALUES ($1, $2, $3)
ON CONFLICT (track_id, tag)
    DO UPDATE SET weight = GREATEST(track_tags.weight, EXCLUDED.weight)
`

type InsertTrackTagParams struct {
	TrackID pgtype.UUID
	Tag     string
	Weight  float64
}

// Upsert one (track, tag); keep the stronger weight when two providers
// agree on a tag with different folksonomy strengths.
func (q *Queries) InsertTrackTag(ctx context.Context, arg InsertTrackTagParams) error {
	_, err := q.db.Exec(ctx, insertTrackTag, arg.TrackID, arg.Tag, arg.Weight)
	return err
}

const listLikedTrackTagsForUser = `-- name: ListLikedTrackTagsForUser :many
SELECT tt.track_id, tt.tag, tt.weight
  FROM track_tags tt
  JOIN general_likes gl ON gl.track_id = tt.track_id
 WHERE gl.user_id = $1
`

// Enriched tags for the user's liked tracks — the like-bonus path in the
// recompute mirrors the play path, so it needs the same tag lookup.
func (q *Queries) ListLikedTrackTagsForUser(ctx context.Context, userID pgtype.UUID) ([]TrackTag, error) {
	rows, err := q.db.Query(ctx, listLikedTrackTagsForUser, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []TrackTag
	for rows.Next() {
		var i TrackTag
		if err := rows.Scan(&i.TrackID, &i.Tag, &i.Weight); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listPlayedTrackTagsForUser = `-- name: ListPlayedTrackTagsForUser :many
SELECT tt.track_id, tt.tag, tt.weight
  FROM track_tags tt
 WHERE tt.track_id IN (
       SELECT DISTINCT pe.track_id
         FROM play_events pe
        WHERE pe.user_id = $1
          AND pe.was_skipped = false
          AND pe.started_at > now() - make_interval(days => $2::int)
   )
`

type ListPlayedTrackTagsForUserParams struct {
	UserID  pgtype.UUID
	Column2 int32
}

// The enriched tags for every track this user played inside the taste
// window, so the recompute can union them into the tag facet alongside
// ID3 genre. $1 = user_id, $2 = window_days. One row per (track, tag).
func (q *Queries) ListPlayedTrackTagsForUser(ctx context.Context, arg ListPlayedTrackTagsForUserParams) ([]TrackTag, error) {
	rows, err := q.db.Query(ctx, listPlayedTrackTagsForUser, arg.UserID, arg.Column2)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []TrackTag
	for rows.Next() {
		var i TrackTag
		if err := rows.Scan(&i.TrackID, &i.Tag, &i.Weight); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTrackTagsForTracks = `-- name: ListTrackTagsForTracks :many
SELECT tt.track_id, tt.tag
  FROM track_tags tt
 WHERE tt.track_id = ANY($1::uuid[])
`

type ListTrackTagsForTracksRow struct {
	TrackID pgtype.UUID
	Tag     string
}

// Enriched tags for a set of candidate tracks (#1534), so the scorer can
// derive each candidate's mood buckets at scoring time. One row per (track,
// tag); the caller filters to mood words via the internal/mood vocabulary.
func (q *Queries) ListTrackTagsForTracks(ctx context.Context, dollar_1 []pgtype.UUID) ([]ListTrackTagsForTracksRow, error) {
	rows, err := q.db.Query(ctx, listTrackTagsForTracks, dollar_1)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListTrackTagsForTracksRow
	for rows.Next() {
		var i ListTrackTagsForTracksRow
		if err := rows.Scan(&i.TrackID, &i.Tag); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTracksMissingTags = `-- name: ListTracksMissingTags :many

SELECT t.id, t.mbid, t.title, a.name AS artist_name, a.mbid AS artist_mbid
  FROM tracks t
  JOIN artists a ON a.id = t.artist_id
 WHERE t.tag_source IS NULL
    OR (t.tag_source = 'none' AND t.tag_sources_version < $1)
 ORDER BY t.id
 LIMIT $2
`

type ListTracksMissingTagsParams struct {
	TagSourcesVersion int32
	Limit             int32
}

type ListTracksMissingTagsRow struct {
	ID         pgtype.UUID
	Mbid       *string
	Title      string
	ArtistName string
	ArtistMbid *string
}

// Track-tag enrichment queries (milestone #160, #1490). The tag enricher
// drains ListTracksMissingTags, fetches from the provider chain, and
// writes the merged top-K via DeleteTrackTags + InsertTrackTag, then
// stamps SetTrackTagSource. Mirrors the coverart artist-enricher shape.
// Tracks eligible for tag enrichment: never processed (tag_source NULL)
// or previously settled 'none' under an older provider version. Returns
// the fields the provider chain needs — recording MBID (nullable) for
// keyed lookups, title + artist name for name-based fallback, and the
// artist MBID (nullable) for MusicBrainz's artist-tag fallback (#1519).
// $1 = current tag_sources_version, $2 = limit.
func (q *Queries) ListTracksMissingTags(ctx context.Context, arg ListTracksMissingTagsParams) ([]ListTracksMissingTagsRow, error) {
	rows, err := q.db.Query(ctx, listTracksMissingTags, arg.TagSourcesVersion, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListTracksMissingTagsRow
	for rows.Next() {
		var i ListTracksMissingTagsRow
		if err := rows.Scan(
			&i.ID,
			&i.Mbid,
			&i.Title,
			&i.ArtistName,
			&i.ArtistMbid,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const setTrackTagSource = `-- name: SetTrackTagSource :exec
UPDATE tracks SET tag_source = $2, tag_sources_version = $3 WHERE id = $1
`

type SetTrackTagSourceParams struct {
	ID                pgtype.UUID
	TagSource         *string
	TagSourcesVersion int32
}

// Stamp the enrichment outcome so the batch drainer skips settled rows.
// $2 = 'lastfm' | 'musicbrainz' | 'mixed' | 'none', $3 = current version.
func (q *Queries) SetTrackTagSource(ctx context.Context, arg SetTrackTagSourceParams) error {
	_, err := q.db.Exec(ctx, setTrackTagSource, arg.ID, arg.TagSource, arg.TagSourcesVersion)
	return err
}
