package resourcemanager

import (
	"context"
	"testing"

	"github.com/tidbcloud/observability/pkg/common/errors"

	"github.com/stretchr/testify/assert"

	v1 "github.com/tidbcloud/observability/api/regionalserver/resourceworker/v1"
	"github.com/tidbcloud/observability/pkg/common/constants"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func Test_iamReaderWriter_CreateAndDelete(t *testing.T) {
	// disturbance term
	err := iamRW.CreateRole(context.TODO(), &v1.IAM{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "disturbance",
			Namespace: constants.ObservabilityNamespace,
		},
		Spec: v1.IAMSpec{
			Aws: v1.AWSIAM{
				AssumeRolePolicyDocument: "assumeRolePolicy",
				Policies: []v1.AWSRolePolicy{
					{
						PolicyDocument: "defaultPolicy",
						PolicyName:     "putS3",
					},
				},
			},
		},
	})
	assert.NoError(t, err)
	defer iamRW.DeleteRole(context.TODO(), "disturbance", constants.ObservabilityNamespace)

	defaultRoleName := "role111"
	defaultRole := &v1.IAM{
		ObjectMeta: metav1.ObjectMeta{
			Name:      defaultRoleName,
			Namespace: constants.ObservabilityNamespace,
			Labels: map[string]string{
				constants.LabelVendor:    "aws",
				constants.LabelRegion:    "us-east-2",
				constants.LabelTenantID:  "defaultTenant",
				constants.LabelProjectID: "defaultProject",
			},
		},
		Spec: v1.IAMSpec{
			Aws: v1.AWSIAM{
				AssumeRolePolicyDocument: "assumeRolePolicy",
				Policies: []v1.AWSRolePolicy{
					{
						PolicyDocument: "defaultPolicy",
						PolicyName:     "putS3",
					},
				},
			},
		},
	}

	exists, err := iamRW.IsRoleExists(context.TODO(), defaultRoleName, constants.ObservabilityNamespace)
	assert.NoError(t, err)
	assert.False(t, exists)

	_, err = iamRW.GetRole(context.TODO(), defaultRoleName, constants.ObservabilityNamespace)
	assert.Error(t, err)
	assert.Equal(t, errors.RoleNotFound, err.(errors.Error).Code())

	err = iamRW.CreateRole(context.TODO(), defaultRole)
	assert.NoError(t, err)

	// conflict
	err = iamRW.CreateRole(context.TODO(), &v1.IAM{
		ObjectMeta: metav1.ObjectMeta{
			Name:      defaultRoleName,
			Namespace: constants.ObservabilityNamespace,
			Labels: map[string]string{
				constants.LabelVendor:    "aws",
				constants.LabelRegion:    "us-east-2",
				constants.LabelTenantID:  "defaultTenant",
				constants.LabelProjectID: "defaultProject",
			},
		},
		Spec: v1.IAMSpec{
			Aws: v1.AWSIAM{
				AssumeRolePolicyDocument: "assumeRolePolicy",
				Policies: []v1.AWSRolePolicy{
					{
						PolicyDocument: "defaultPolicy",
						PolicyName:     "putS3",
					},
				},
			},
		},
	})
	assert.Error(t, err)
	assert.Equal(t, errors.DuplicatedRoleName, err.(errors.Error).Code())

	exists, err = iamRW.IsRoleExists(context.TODO(), defaultRoleName, constants.ObservabilityNamespace)
	assert.NoError(t, err)
	assert.True(t, exists)

	defaultRole.Spec.Aws.AssumeRolePolicyDocument = "updatedDocument"
	err = iamRW.UpdateRole(context.TODO(), defaultRole)
	assert.NoError(t, err)

	role, err := iamRW.GetRole(context.TODO(), defaultRoleName, constants.ObservabilityNamespace)
	assert.NoError(t, err)
	assert.Equal(t, defaultRoleName, role.Name)
	assert.Equal(t, "updatedDocument", role.Spec.Aws.AssumeRolePolicyDocument)

	err = iamRW.DeleteRole(context.TODO(), defaultRoleName, constants.ObservabilityNamespace)
	assert.NoError(t, err)

	exists, err = iamRW.IsRoleExists(context.TODO(), defaultRoleName, constants.ObservabilityNamespace)
	assert.NoError(t, err)
	assert.False(t, exists)
}
func Test_iamReaderWriter_GetAndDeleteRoles(t *testing.T) {
	// Create roles for testing
	roles := []*v1.IAM{
		{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "role1",
				Namespace: constants.ObservabilityNamespace,
				Labels: map[string]string{
					"env": "test",
				},
			},
			Spec: v1.IAMSpec{
				Aws: v1.AWSIAM{
					AssumeRolePolicyDocument: "assumeRolePolicy1",
					Policies: []v1.AWSRolePolicy{
						{
							PolicyDocument: "policy1",
							PolicyName:     "policyName1",
						},
					},
				},
			},
		},
		{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "role2",
				Namespace: constants.ObservabilityNamespace,
				Labels: map[string]string{
					"env": "test",
				},
			},
			Spec: v1.IAMSpec{
				Aws: v1.AWSIAM{
					AssumeRolePolicyDocument: "assumeRolePolicy2",
					Policies: []v1.AWSRolePolicy{
						{
							PolicyDocument: "policy2",
							PolicyName:     "policyName2",
						},
					},
				},
			},
		},
	}

	for _, role := range roles {
		err := iamRW.CreateRole(context.TODO(), role)
		assert.NoError(t, err)
	}

	// Verify roles exist
	for _, role := range roles {
		exists, err := iamRW.IsRoleExists(context.TODO(), role.Name, constants.ObservabilityNamespace)
		assert.NoError(t, err)
		assert.True(t, exists)
	}

	iamList, err := iamRW.GetRoles(context.TODO(), constants.ObservabilityNamespace, map[string]string{"env": "test"})
	assert.NoError(t, err)
	assert.Equal(t, 2, len(iamList.Items))

	// Delete roles with label selector
	err = iamRW.DeleteRoles(context.TODO(), constants.ObservabilityNamespace, map[string]string{"env": "test"})
	assert.NoError(t, err)

	// Verify roles are deleted
	for _, role := range roles {
		exists, err := iamRW.IsRoleExists(context.TODO(), role.Name, constants.ObservabilityNamespace)
		assert.NoError(t, err)
		assert.False(t, exists)
	}
}
