package integration

import (
	"fmt"
	"os"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/ram"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
)

var role_doc = `{
		"Statement": [
			{
				"Action": "sts:AssumeRole",
				"Effect": "Allow",
				"Principal": {
					"RAM": [
						"acs:ram::%s:root"
					]
				}
			}
		],
		"Version": "1"
	}`

var (
	username = "test-user-" + os.Getenv("CONCURRENT_ID")
	rolename = "test-role-" + os.Getenv("CONCURRENT_ID")
	rolearn  = fmt.Sprintf("acs:ram::%s:role/%s", os.Getenv("USER_ID"), rolename)
)

var ecsEndpoint = "ecs." + os.Getenv("REGION_ID") + ".aliyuncs.com"

func newRamClient() (*ram.Client, error) {
	return ram.NewClientWithAccessKey(os.Getenv("REGION_ID"), os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"))
}

func createRole(userid string) (err error) {
	client, err := newRamClient()
	if err != nil {
		return
	}

	createRequest := ram.CreateCreateRoleRequest()
	createRequest.Scheme = "HTTPS"
	createRequest.RoleName = rolename
	createRequest.AssumeRolePolicyDocument = fmt.Sprintf(role_doc, userid)
	_, err = client.CreateRole(createRequest)
	return
}

func ensureRole(userid string) (err error) {
	client, err := newRamClient()
	if err != nil {
		return
	}
	request := ram.CreateGetRoleRequest()
	request.RoleName = rolename
	request.Scheme = "HTTPS"
	_, err = client.GetRole(request)
	if err != nil {
		if se, ok := err.(*errors.ServerError); ok {
			if se.ErrorCode() == "EntityNotExist.Role" {
				// 如果角色不存在，则创建
				err = createRole(userid)
				return
			}
		}
		return
	}

	return
}

func createUser() (response *ram.CreateUserResponse, err error) {
	client, err := newRamClient()
	if err != nil {
		return
	}
	createRequest := ram.CreateCreateUserRequest()
	createRequest.Scheme = "HTTPS"
	createRequest.UserName = username
	return client.CreateUser(createRequest)
}

func ensureUser() (err error) {
	client, err := newRamClient()
	if err != nil {
		return
	}

	// 查询用户
	getUserRequest := ram.CreateGetUserRequest()
	getUserRequest.UserName = username
	getUserRequest.Scheme = "HTTPS"
	_, err = client.GetUser(getUserRequest)
	if err != nil {
		if se, ok := err.(*errors.ServerError); ok {
			if se.ErrorCode() == "EntityNotExist.User" {
				// 如果用户不存在，则创建
				_, err = createUser()
				return
			}
		}
		return
	}

	return
}

func createAttachPolicyToUser() error {
	listRequest := ram.CreateListPoliciesForUserRequest()
	listRequest.UserName = username
	listRequest.Scheme = "HTTPS"
	client, err := newRamClient()
	if err != nil {
		return err
	}
	listResponse, err := client.ListPoliciesForUser(listRequest)
	if err != nil {
		return err
	}
	for _, policy := range listResponse.Policies.Policy {
		if policy.PolicyName == "AliyunSTSAssumeRoleAccess" {
			return nil
		}
	}
	createRequest := ram.CreateAttachPolicyToUserRequest()
	createRequest.Scheme = "HTTPS"
	createRequest.PolicyName = "AliyunSTSAssumeRoleAccess"
	createRequest.UserName = username
	createRequest.PolicyType = "System"
	_, err = client.AttachPolicyToUser(createRequest)
	if err != nil {
		return err
	}
	return nil
}

func createAttachPolicyToRole() error {
	listRequest := ram.CreateListPoliciesForRoleRequest()
	listRequest.RoleName = rolename
	listRequest.Scheme = "HTTPS"
	client, err := newRamClient()
	if err != nil {
		return err
	}
	listResponse, err := client.ListPoliciesForRole(listRequest)
	if err != nil {
		return err
	}
	for _, policy := range listResponse.Policies.Policy {
		if policy.PolicyName == "AdministratorAccess" {
			return nil
		}
	}
	createRequest := ram.CreateAttachPolicyToRoleRequest()
	createRequest.Scheme = "HTTPS"
	createRequest.PolicyName = "AdministratorAccess"
	createRequest.RoleName = rolename
	createRequest.PolicyType = "System"
	_, err = client.AttachPolicyToRole(createRequest)
	if err != nil {
		return err
	}
	return nil
}

func createAccessKey() (id string, secret string, err error) {
	client, err := newRamClient()
	if err != nil {
		return
	}
	listrequest := ram.CreateListAccessKeysRequest()
	listrequest.UserName = username
	listrequest.Scheme = "HTTPS"
	listresponse, err := client.ListAccessKeys(listrequest)
	if err != nil {
		return
	}
	if listresponse.AccessKeys.AccessKey != nil {
		if len(listresponse.AccessKeys.AccessKey) >= 2 {
			accesskey := listresponse.AccessKeys.AccessKey[0]
			deleterequest := ram.CreateDeleteAccessKeyRequest()
			deleterequest.UserAccessKeyId = accesskey.AccessKeyId
			deleterequest.UserName = username
			deleterequest.Scheme = "HTTPS"
			_, err = client.DeleteAccessKey(deleterequest)
			if err != nil {
				return
			}
		}
	}
	request := ram.CreateCreateAccessKeyRequest()
	request.Scheme = "HTTPS"
	request.UserName = username
	response, err := client.CreateAccessKey(request)
	if err != nil {
		return
	}

	id = response.AccessKey.AccessKeyId
	secret = response.AccessKey.AccessKeySecret
	return
}

func createAssumeRole() (response *sts.AssumeRoleResponse, err error) {
	err = ensureUser()
	if err != nil {
		return
	}

	subaccesskeyid, subaccesskeysecret, err := createAccessKey()
	if err != nil {
		return
	}

	err = ensureRole(os.Getenv("USER_ID"))
	if err != nil {
		return
	}

	err = createAttachPolicyToUser()
	if err != nil {
		return
	}
	request := sts.CreateAssumeRoleRequest()
	request.RoleArn = rolearn
	request.RoleSessionName = "alice_test"
	request.Scheme = "HTTPS"
	client, err := sts.NewClientWithAccessKey(os.Getenv("REGION_ID"), subaccesskeyid, subaccesskeysecret)
	if err != nil {
		return
	}
	response, err = client.AssumeRole(request)
	return
}
