package tags

import (
	"context"
	"errors"
	"net/http"
	"net/http/httptest"
	"strconv"
	"testing"
)

func newLastfmProvider(enabled bool, key string) *lastfmProvider {
	p := &lastfmProvider{client: newHTTPClient(httpClientOptions{
		Name: "lastfm", MaxRetries: 1, TreatAuthAsTransient: true,
	})}
	_ = p.Configure(ProviderSettings{Enabled: enabled, APIKey: key})
	return p
}

func TestNormalizeLastfmTags(t *testing.T) {
	got := tagsByName(normalizeLastfmTags([]lastfmTag{
		{Name: "indie", Count: 100},
		{Name: "dream pop", Count: 40},
		{Name: "zero-drop", Count: 0},
		{Name: "", Count: 50},
		{Name: "clamp", Count: 150}, // >100 clamps to 1.0
	}))
	if len(got) != 3 {
		t.Fatalf("want 3 tags, got %v", got)
	}
	if got["indie"] != 1.0 || got["dream pop"] != 0.4 || got["clamp"] != 1.0 {
		t.Errorf("weights = %v", got)
	}
}

func TestLastfmFetch_GatedOff(t *testing.T) {
	// Enabled but unkeyed → ErrNotFound.
	if _, err := newLastfmProvider(true, "").FetchTrackTags(context.Background(),
		TrackRef{ArtistName: "A", Title: "B"}); !errors.Is(err, ErrNotFound) {
		t.Errorf("unkeyed: err = %v, want ErrNotFound", err)
	}
	// Keyed but disabled → ErrNotFound.
	if _, err := newLastfmProvider(false, "k").FetchTrackTags(context.Background(),
		TrackRef{ArtistName: "A", Title: "B"}); !errors.Is(err, ErrNotFound) {
		t.Errorf("disabled: err = %v, want ErrNotFound", err)
	}
	// Keyed + enabled but missing artist/title → ErrNotFound.
	if _, err := newLastfmProvider(true, "k").FetchTrackTags(context.Background(),
		TrackRef{MBID: "x"}); !errors.Is(err, ErrNotFound) {
		t.Errorf("no artist/title: err = %v, want ErrNotFound", err)
	}
}

func TestLastfmFetch_ParsesTags(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		_, _ = w.Write([]byte(`{"toptags":{"tag":[{"name":"shoegaze","count":100},{"name":"90s","count":30}]}}`))
	}))
	defer srv.Close()
	old := lastfmBaseURL
	lastfmBaseURL = srv.URL + "/"
	defer func() { lastfmBaseURL = old }()

	tags, err := newLastfmProvider(true, "k").FetchTrackTags(context.Background(),
		TrackRef{ArtistName: "Slowdive", Title: "Alison"})
	if err != nil {
		t.Fatalf("fetch: %v", err)
	}
	m := tagsByName(tags)
	if m["shoegaze"] != 1.0 || m["90s"] != 0.3 {
		t.Errorf("weights = %v", m)
	}
}

func TestLastfmFetch_ErrorCodes(t *testing.T) {
	cases := []struct {
		name      string
		errorCode int
		want      error
	}{
		{"not-found", 6, ErrNotFound},
		{"transient-rate-limit", 29, ErrTransient},
		{"transient-unavailable", 16, ErrTransient},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
				_, _ = w.Write([]byte(`{"error":` + strconv.Itoa(c.errorCode) + `,"message":"x"}`))
			}))
			defer srv.Close()
			old := lastfmBaseURL
			lastfmBaseURL = srv.URL + "/"
			defer func() { lastfmBaseURL = old }()

			_, err := newLastfmProvider(true, "k").FetchTrackTags(context.Background(),
				TrackRef{ArtistName: "A", Title: "B"})
			if !errors.Is(err, c.want) {
				t.Errorf("error %d: got %v, want %v", c.errorCode, err, c.want)
			}
		})
	}
}
