-- name: CreateLidarrRequest :one
INSERT INTO lidarr_requests (
    user_id, kind,
    lidarr_artist_mbid, lidarr_album_mbid, lidarr_track_mbid,
    artist_name, album_title, track_title
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *;

-- name: GetLidarrRequestByID :one
SELECT * FROM lidarr_requests WHERE id = $1;

-- name: ListLidarrRequestsForUser :many
SELECT * FROM lidarr_requests
WHERE user_id = $1
ORDER BY requested_at DESC
LIMIT $2;

-- name: ListLidarrRequestsByStatus :many
SELECT * FROM lidarr_requests
WHERE status = $1
ORDER BY requested_at DESC
LIMIT $2;

-- name: ListApprovedLidarrRequestsForReconcile :many
SELECT * FROM lidarr_requests
WHERE status = 'approved'
ORDER BY decided_at ASC
LIMIT $1;

-- name: ApproveLidarrRequest :one
UPDATE lidarr_requests
   SET status                = 'approved',
       quality_profile_id    = $2,
       root_folder_path      = $3,
       decided_at            = now(),
       decided_by            = $4,
       updated_at            = now()
 WHERE id = $1 AND status = 'pending'
 RETURNING *;

-- name: RejectLidarrRequest :one
UPDATE lidarr_requests
   SET status     = 'rejected',
       notes      = $2,
       decided_at = now(),
       decided_by = $3,
       updated_at = now()
 WHERE id = $1 AND status = 'pending'
 RETURNING *;

-- name: CancelLidarrRequest :one
-- $2 serves as both the ownership guard (user_id = $2) and the
-- decided_by audit field. The generated parameter struct names it
-- DecidedBy — callers must pass the cancelling user's UUID, and
-- a wrong UUID will silently no-op (zero rows updated) rather than
-- erroring at the SQL layer.
UPDATE lidarr_requests
   SET status     = 'rejected',
       notes      = 'cancelled by user',
       decided_at = now(),
       decided_by = $2,
       updated_at = now()
 WHERE id = $1 AND user_id = $2 AND status = 'pending'
 RETURNING *;

-- name: CompleteLidarrRequest :one
-- Reconciler transitions an approved request to completed when its
-- target track/album/artist has appeared in the library. Callers
-- should set ONLY the matched_*_id corresponding to the request's
-- kind and pass pgtype.UUID{} (Valid: false) for the others —
-- per-kind one-of-three is the contract, NULL for the others
-- preserves auditability if the matched row is later evicted.
UPDATE lidarr_requests
   SET status            = 'completed',
       matched_track_id  = $2,
       matched_album_id  = $3,
       matched_artist_id = $4,
       completed_at      = now(),
       updated_at        = now()
 WHERE id = $1 AND status = 'approved'
 RETURNING *;

-- name: HasNonTerminalRequestForMBID :one
-- Returns true if any user has a pending/approved/completed request
-- whose MBID matches at the given level. Used to set the `requested`
-- flag on /api/lidarr/search responses. Terminal-status (rejected,
-- failed) rows do not count. The same MBID parameter is checked
-- against artist/album/track columns based on kind.
SELECT EXISTS (
    SELECT 1 FROM lidarr_requests
    WHERE status IN ('pending', 'approved', 'completed')
      AND ((kind = 'artist' AND lidarr_artist_mbid = @mbid)
        OR (kind = 'album'  AND lidarr_album_mbid  = @mbid)
        OR (kind = 'track'  AND lidarr_track_mbid  = @mbid))
);

-- name: GetNonTerminalRequestForMBID :one
-- Returns the oldest non-terminal (pending/approved/completed) request
-- whose own-kind MBID matches @mbid, or pgx.ErrNoRows when none. Create()
-- uses this to dedupe: a re-request for something already in flight
-- returns the existing row instead of inserting a duplicate. MBIDs are
-- globally unique per entity type, so the cross-column OR cannot
-- false-match (an artist MBID never collides with an album/track MBID).
SELECT * FROM lidarr_requests
 WHERE status IN ('pending', 'approved', 'completed')
   AND ((kind = 'artist' AND lidarr_artist_mbid = @mbid)
     OR (kind = 'album'  AND lidarr_album_mbid  = @mbid)
     OR (kind = 'track'  AND lidarr_track_mbid  = @mbid))
 ORDER BY requested_at ASC
 LIMIT 1;

-- name: MarkLidarrRequestAddConfirmed :exec
-- Idempotently records that Lidarr accepted the add for an approved
-- request. The lidarr_add_confirmed_at IS NULL guard makes a redundant
-- reconciler retry a no-op rather than bumping updated_at every tick.
UPDATE lidarr_requests
   SET lidarr_add_confirmed_at = now(),
       updated_at              = now()
 WHERE id = $1
   AND status = 'approved'
   AND lidarr_add_confirmed_at IS NULL;
