package monstersirenfetch_test

import (
	_ "embed"
	"errors"
	"os"
	"reflect"
	"testing"

	. "git.gensokyo.uk/yonah/monstersirenfetch"
)

//go:embed testdata/song.json
var songJSON []byte

func TestSong(t *testing.T) {
	checkJSONRoundTrip(t, SongResponse{Data: Song{
		CID:       48794,
		Name:      "Warm and Small Light",
		AlbumCID:  6660,
		SourceURL: "https://res01.hycdn.cn/04ce5de54bb52eb85008644d541d40fa/68CA0442/siren/audio/20240709/a7f650238eaefc9c30a9627d7f78d819.wav",
		LyricURL:  "https://web.hycdn.cn/siren/lyric/20240709/4a10c70629b68a187fdbef4a27bd32d8.lrc",
		Artists:   []string{"塞壬唱片-MSR"},
	}}, songJSON)

	t.Run("copy", func(t *testing.T) {
		testCases := []struct {
			name    string
			a       *Song
			variant int
			want    Song
			wantOk  bool
		}{
			{"nil", nil, SongVariantBase, Song{CID: -0xdeadbeef}, false},
			{"current", new(Song), SongVariantCurrent, Song{}, true},
			{"full guard", new(Song), SongVariantFull, Song{CID: -0xdeadbeef}, false},

			{"current full", &Song{
				SourceURL: "\x00",
			}, SongVariantCurrent, Song{
				SourceURL: "\x00",
			}, true},

			{"oob", &Song{
				SourceURL: "\x00",
			}, 0xbad, Song{CID: -0xdeadbeef}, false},

			{"full", &Song{
				CID:       48794,
				Name:      "Warm and Small Light",
				AlbumCID:  6660,
				SourceURL: "https://res01.hycdn.cn/04ce5de54bb52eb85008644d541d40fa/68CA0442/siren/audio/20240709/a7f650238eaefc9c30a9627d7f78d819.wav",
				LyricURL:  "https://web.hycdn.cn/siren/lyric/20240709/4a10c70629b68a187fdbef4a27bd32d8.lrc",
				Artists:   []string{"塞壬唱片-MSR"},
			}, SongVariantFull, Song{
				CID:       48794,
				Name:      "Warm and Small Light",
				AlbumCID:  6660,
				SourceURL: "https://res01.hycdn.cn/04ce5de54bb52eb85008644d541d40fa/68CA0442/siren/audio/20240709/a7f650238eaefc9c30a9627d7f78d819.wav",
				LyricURL:  "https://web.hycdn.cn/siren/lyric/20240709/4a10c70629b68a187fdbef4a27bd32d8.lrc",
				Artists:   []string{"塞壬唱片-MSR"},
			}, true},

			{"base", &Song{
				CID:       48794,
				Name:      "Warm and Small Light",
				AlbumCID:  6660,
				SourceURL: "https://res01.hycdn.cn/04ce5de54bb52eb85008644d541d40fa/68CA0442/siren/audio/20240709/a7f650238eaefc9c30a9627d7f78d819.wav",
				LyricURL:  "https://web.hycdn.cn/siren/lyric/20240709/4a10c70629b68a187fdbef4a27bd32d8.lrc",
				Artists:   []string{"塞壬唱片-MSR"},
			}, SongVariantBase, Song{
				CID:      48794,
				Name:     "Warm and Small Light",
				AlbumCID: 6660,
				Artists:  []string{"塞壬唱片-MSR"},
			}, true},
		}
		for _, tc := range testCases {
			t.Run(tc.name, func(t *testing.T) {
				got := Song{CID: -0xdeadbeef}
				if ok := tc.a.Copy(&got, tc.variant); ok != tc.wantOk {
					t.Errorf("Copy: ok = %v, want %v", ok, tc.wantOk)
				}
				if !reflect.DeepEqual(got, tc.want) {
					t.Errorf("Copy: %#v, want %#v", got, tc.want)
				}
			})
		}
	})
}

func TestSongEnrich(t *testing.T) {
	testCases := []struct {
		name    string
		base    Song
		n       Net
		want    Song
		wantErr error
	}{
		{"get", Song{
			CID:      48794,
			Name:     "Warm and Small Light",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNet{}, Song{}, errors.New("url https://monster-siren.hypergryph.com/api/song/048794 requested, but is not present")},

		{"invalid response", Song{
			CID:      48794,
			Name:     "Warm and Small Light",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNet{
			makeSongPath(48794): []byte{0},
		}, Song{}, errors.Join(newSyntaxError("invalid character '\\x00' looking for beginning of value", 1))},

		{"close", Song{
			CID:      48794,
			Name:     "Warm and Small Light",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNetErrorCloser{
			makeSongPath(48794): songJSON,
		}, Song{}, os.ErrInvalid},

		{"inconsistent cid", Song{
			CID:      0xdeadbeef,
			Name:     "Warm and Small Light",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNet{
			makeSongPath(0xdeadbeef): songJSON,
		}, Song{}, &InconsistentEnrichError[StringInt]{
			Field:    "cid",
			Value:    0xdeadbeef,
			NewValue: 48794,
		}},

		{"inconsistent name", Song{
			CID:      48794,
			Name:     "Warm and Small Light\x00",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNet{
			makeSongPath(48794): songJSON,
		}, Song{}, &InconsistentEnrichError[string]{
			Field:    "name",
			Value:    "Warm and Small Light\x00",
			NewValue: "Warm and Small Light",
		}},

		{"inconsistent albumCid", Song{
			CID:      48794,
			Name:     "Warm and Small Light",
			AlbumCID: -1,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNet{
			makeSongPath(48794): songJSON,
		}, Song{}, &InconsistentEnrichError[StringInt]{
			Field:    "albumCid",
			Value:    -1,
			NewValue: 6660,
		}},

		{"inconsistent artists", Song{
			CID:      48794,
			Name:     "Warm and Small Light",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR", "\x00"},
		}, stubNet{
			makeSongPath(48794): songJSON,
		}, Song{}, &InconsistentEnrichError[[]string]{
			Field:    "artists",
			Value:    []string{"塞壬唱片-MSR", "\x00"},
			NewValue: []string{"塞壬唱片-MSR"},
		}},

		{"valid", Song{
			CID:      48794,
			Name:     "Warm and Small Light",
			AlbumCID: 6660,
			Artists:  []string{"塞壬唱片-MSR"},
		}, stubNet{
			makeSongPath(48794): songJSON,
		}, Song{
			CID:       48794,
			Name:      "Warm and Small Light",
			AlbumCID:  6660,
			SourceURL: "https://res01.hycdn.cn/04ce5de54bb52eb85008644d541d40fa/68CA0442/siren/audio/20240709/a7f650238eaefc9c30a9627d7f78d819.wav",
			LyricURL:  "https://web.hycdn.cn/siren/lyric/20240709/4a10c70629b68a187fdbef4a27bd32d8.lrc",
			MvURL:     "", MvCoverURL: "",
			Artists: []string{"塞壬唱片-MSR"},
		}, nil},
	}
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			s := new(Song)
			*s = tc.base
			if err := s.Enrich(t.Context(), tc.n); !reflect.DeepEqual(err, tc.wantErr) {
				t.Errorf("Enrich: error = %v, want %v", err, tc.wantErr)
			}
			if tc.wantErr == nil && !reflect.DeepEqual(s, &tc.want) {
				t.Errorf("Enrich: %#v, want %#v", s, &tc.want)
			}
		})
	}

	t.Run("invalid", func(t *testing.T) {
		t.Run("nil", func(t *testing.T) {
			if err := (*Song)(nil).Enrich(t.Context(), nil); !errors.Is(err, os.ErrInvalid) {
				t.Errorf("Enrich: error = %v", err)
			}
		})
		t.Run("full", func(t *testing.T) {
			if err := (&Song{SourceURL: "\x00"}).Enrich(t.Context(), nil); !errors.Is(err, os.ErrInvalid) {
				t.Errorf("Enrich: error = %v", err)
			}
		})
	})
}

func makeSongPath(cid StringInt) string {
	return APIPrefix + "/song/" + cid.String()
}
