package ec

import (
	"testing"

	"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
	"github.com/stretchr/testify/assert"
)

func TestEcShardsFromString(t *testing.T) {
	tests := []struct {
		name    string
		in      string
		want    []*ShardRef
		wantErr bool
	}{
		{
			name: "single id",
			in:   "2",
			want: []*ShardRef{{ShardID: 2}},
		},
		{
			name: "list of ids",
			in:   "0, 3 ,5",
			want: []*ShardRef{{ShardID: 0}, {ShardID: 3}, {ShardID: 5}},
		},
		{
			name: "qualified keeps host:port",
			in:   "3@10.200.18.88:9007",
			want: []*ShardRef{{ShardID: 3, NodeAddress: "10.200.18.88:9007"}},
		},
		{
			name: "mixed bare and qualified",
			in:   "2,3@10.200.18.88:9007",
			want: []*ShardRef{{ShardID: 2}, {ShardID: 3, NodeAddress: "10.200.18.88:9007"}},
		},
		{
			name:    "colon without node marker is not a shard ID",
			in:      "3:10.200.18.88:9007",
			wantErr: true,
		},
		{
			// shard IDs beyond the default 10+4 total are valid on custom-ratio volumes.
			name: "shard id within MaxShardCount",
			in:   "20",
			want: []*ShardRef{{ShardID: 20}},
		},
		{
			name:    "shard id at MaxShardCount is rejected",
			in:      "32",
			wantErr: true,
		},
		{
			name:    "negative shard id",
			in:      "-1",
			wantErr: true,
		},
		{
			// must not wrap through uint32 into a valid-looking shard ID (4294967301 -> 5)
			name:    "out-of-range shard id does not wrap",
			in:      "4294967301",
			wantErr: true,
		},
		{
			name:    "non-numeric shard id",
			in:      "abc",
			wantErr: true,
		},
		{
			name:    "empty element",
			in:      "1,,2",
			wantErr: true,
		},
	}

	// guard the assumption the bound test relies on
	assert.Equal(t, uint32(32), uint32(erasure_coding.MaxShardCount))

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ShardRefsFromString(tt.in)
			if tt.wantErr {
				assert.Error(t, err)
				return
			}
			assert.NoError(t, err)
			assert.Equal(t, tt.want, got)
		})
	}
}

// the printed topology form must parse back, so entries can be copied verbatim.
func TestEcShardStringRoundTrips(t *testing.T) {
	for _, s := range []*ShardRef{
		{ShardID: 2},
		{ShardID: 3, NodeAddress: "10.200.18.88:9007"},
	} {
		got, err := ShardRefsFromString(s.String())
		assert.NoError(t, err)
		assert.Equal(t, []*ShardRef{s}, got)
	}
}
