package service

import (
	"context"
	"strconv"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/config-center/internal/db"
	pb "github.com/tidbcloud/config-center/proto/config_center"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/structpb"
)

func TestCreateMetaProfileComponentVersions(t *testing.T) {
	svc := &ConfigCenterService{DB: db.NewMockDB()}

	profile, err := svc.CreateMetaProfile(context.Background(), &pb.CreateMetaProfileRequest{
		ClusterType: pb.ClusterType_DEDICATED_TIDB,
		ProfileName: "profile",
		Description: "test profile",
		ComponentVersions: map[string]string{
			"tidb": "v8.5.4",
			"tikv": "v8.5.4",
		},
		ComponentImageTags: map[string]string{
			"tikv": "tikv-hotfix",
		},
		ConfigCustomTemplates: map[string]int64{
			"tikv": 100,
		},
	})
	require.NoError(t, err)

	assert.Equal(t, "v8.5.4", profile.GetComponentVersions()["tidb"])
	assert.Equal(t, "v8.5.4", profile.GetComponentVersions()["tikv"])
	assert.Equal(t, "tikv-hotfix", profile.GetComponentImageTags()["tikv"])
	assert.Equal(t, int64(100), profile.GetConfigCustomTemplates()["tikv"])

	got, err := svc.GetMetaProfile(context.Background(), &pb.GetMetaProfileRequest{
		ClusterType: pb.ClusterType_DEDICATED_TIDB,
		ProfileId:   profile.GetProfileId(),
	})
	require.NoError(t, err)
	assert.Equal(t, profile.GetComponentVersions(), got.GetComponentVersions())
	assert.Equal(t, profile.GetComponentImageTags(), got.GetComponentImageTags())
}

func TestCreateMetaProfileRejectsTagWithoutVersion(t *testing.T) {
	svc := &ConfigCenterService{DB: db.NewMockDB()}

	_, err := svc.CreateMetaProfile(context.Background(), &pb.CreateMetaProfileRequest{
		ClusterType: pb.ClusterType_DEDICATED_TIDB,
		ProfileName: "profile",
		Description: "test profile",
		ComponentImageTags: map[string]string{
			"tidb": "tidb-hotfix",
		},
	})

	require.Error(t, err)
	assert.Equal(t, codes.InvalidArgument, status.Code(err))
}

func TestListMetaProfilesFiltersByExactProfileName(t *testing.T) {
	svc := &ConfigCenterService{DB: db.NewMockDB()}

	for _, name := range []string{"target", "target-extra", "other"} {
		_, err := svc.CreateMetaProfile(context.Background(), &pb.CreateMetaProfileRequest{
			ClusterType: pb.ClusterType_DEDICATED_TIDB,
			ProfileName: name,
			Description: name,
			ComponentVersions: map[string]string{
				"tidb": "v8.5.4",
			},
		})
		require.NoError(t, err)
	}

	name := "target"
	resp, err := svc.ListMetaProfiles(context.Background(), &pb.ListMetaProfilesRequest{
		ClusterType: pb.ClusterType_DEDICATED_TIDB,
		ProfileName: &name,
	})
	require.NoError(t, err)
	require.Len(t, resp.GetProfiles(), 1)
	assert.Equal(t, int64(1), resp.GetTotal())
	assert.Equal(t, "target", resp.GetProfiles()[0].GetProfileName())
}

func TestListMetaProfilesPagination(t *testing.T) {
	svc := &ConfigCenterService{DB: db.NewMockDB()}

	for _, name := range []string{"profile-a", "profile-b", "profile-c"} {
		_, err := svc.CreateMetaProfile(context.Background(), &pb.CreateMetaProfileRequest{
			ClusterType: pb.ClusterType_DEDICATED_TIDB,
			ProfileName: name,
			Description: name,
			ComponentVersions: map[string]string{
				"tidb": "v8.5.4",
			},
		})
		require.NoError(t, err)
	}

	resp, err := svc.ListMetaProfiles(context.Background(), &pb.ListMetaProfilesRequest{
		ClusterType: pb.ClusterType_DEDICATED_TIDB,
		PageSize:    2,
		Page:        2,
	})
	require.NoError(t, err)
	assert.Equal(t, int64(3), resp.GetTotal())
	require.Len(t, resp.GetProfiles(), 1)
	assert.Equal(t, "profile-c", resp.GetProfiles()[0].GetProfileName())
}

func TestListMetaProfilesDefaultPageSize(t *testing.T) {
	svc := &ConfigCenterService{DB: db.NewMockDB()}

	for i := 0; i < 51; i++ {
		_, err := svc.CreateMetaProfile(context.Background(), &pb.CreateMetaProfileRequest{
			ClusterType: pb.ClusterType_DEDICATED_TIDB,
			ProfileName: "profile-" + strconv.Itoa(i),
			Description: "profile",
			ComponentVersions: map[string]string{
				"tidb": "v8.5.4",
			},
		})
		require.NoError(t, err)
	}

	resp, err := svc.ListMetaProfiles(context.Background(), &pb.ListMetaProfilesRequest{
		ClusterType: pb.ClusterType_DEDICATED_TIDB,
	})
	require.NoError(t, err)
	assert.Equal(t, int64(51), resp.GetTotal())
	assert.Len(t, resp.GetProfiles(), int(defaultMetaProfileListPageSize))
}

func TestTemplate2MetaProfileFillsLegacyVersionForTagOnlyProfiles(t *testing.T) {
	profile := template2MetaProfile(&pb.ConfigurationTemplate{
		ClusterType:       pb.ClusterType_DEDICATED_TIDB,
		TemplateId:        1,
		TemplateName:      "legacy",
		ConfigurationType: pb.CONFIG_CENTER_INTERNAL_META_PROFILE,
		Data: map[string]*pb.ParamItem{
			"description": {
				Value: structpb.NewStringValue("legacy profile"),
			},
			metaProfileComponentTagPrefix + "tidb": {
				Value: structpb.NewStringValue("tidb-hotfix"),
			},
		},
	})

	assert.Equal(t, "tidb-hotfix", profile.GetComponentImageTags()["tidb"])
	assert.Equal(t, legacyMetaProfileComponentVersion, profile.GetComponentVersions()["tidb"])
}
