package lidarr

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"
)

// UnmonitorTrack flips Lidarr's `monitored` flag to false on the track
// matching trackMbid (a MusicBrainz id, aka Lidarr's `foreignTrackId`).
// Used by the M7 #372 admin "Remove from library" flow when the operator
// requests `?unmonitor=true` so Lidarr's monitor doesn't search for a
// replacement after we delete the local file + DB rows.
//
// Lidarr's monitor API takes its own internal numeric id, not the mbid,
// so this is a three-step walk:
//
//  1. GET /api/v1/album?foreignAlbumId={albumMbid} — find the album's
//     internal Lidarr id. albumMbid is the parent album's mbid; the
//     caller (tracks service) passes it because looking it up from the
//     trackMbid alone would mean either a dedicated Lidarr endpoint
//     that doesn't exist or scanning the entire library.
//  2. GET /api/v1/track?albumId={lidarr_album_id} — list the album's
//     tracks, each with its internal id and foreignTrackId.
//  3. PUT /api/v1/track/monitor — body `{trackIds:[id], monitored:false}`.
//
// Returns ErrNotFound when the album or track isn't in Lidarr's library
// (already removed, or the track was never imported). Network / auth /
// 5xx errors propagate as typed sentinel errors so the tracks service
// can decide whether to surface a `lidarr_unmonitor_failed` flag.
func (c *Client) UnmonitorTrack(ctx context.Context, trackMbid, albumMbid string) error {
	if trackMbid == "" {
		return fmt.Errorf("lidarr: empty track mbid")
	}
	if albumMbid == "" {
		return fmt.Errorf("lidarr: empty album mbid")
	}

	// Step 1: resolve album mbid → Lidarr album id.
	album, err := c.LookupAlbumByMBID(ctx, albumMbid)
	if err != nil {
		return err
	}
	if album.ID == 0 {
		return ErrNotFound
	}

	// Step 2: list tracks under that album, find the one whose
	// foreignTrackId matches.
	q := url.Values{"albumId": []string{strconv.Itoa(album.ID)}}
	resp, err := c.get(ctx, "/api/v1/track", q)
	if err != nil {
		return err
	}
	defer func() { _ = resp.Body.Close() }()

	var tracks []struct {
		ID             int    `json:"id"`
		ForeignTrackID string `json:"foreignTrackId"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&tracks); err != nil {
		return fmt.Errorf("%w: decode tracks: %v", ErrInvalidPayload, err)
	}
	var lidarrTrackID int
	for _, t := range tracks {
		if t.ForeignTrackID == trackMbid {
			lidarrTrackID = t.ID
			break
		}
	}
	if lidarrTrackID == 0 {
		return ErrNotFound
	}

	// Step 3: PUT the monitor toggle.
	body, err := json.Marshal(map[string]any{
		"trackIds":  []int{lidarrTrackID},
		"monitored": false,
	})
	if err != nil {
		return fmt.Errorf("%w: marshal: %v", ErrInvalidPayload, err)
	}
	putResp, err := c.put(ctx, "/api/v1/track/monitor", body)
	if err != nil {
		return err
	}
	_ = putResp.Body.Close()
	return nil
}
