package middlewares

import (
	"fmt"

	"github.com/snyk/driftctl/pkg/resource"
	resourceaws "github.com/snyk/driftctl/pkg/resource/aws"
)

// Split Policy attachment when there is multiple user and groups and generate a repeatable id
type IamPolicyAttachmentExpander struct {
	resourceFactory resource.ResourceFactory
}

func NewIamPolicyAttachmentExpander(resourceFactory resource.ResourceFactory) IamPolicyAttachmentExpander {
	return IamPolicyAttachmentExpander{
		resourceFactory,
	}
}

func (m IamPolicyAttachmentExpander) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error {
	var newStateResources = make([]*resource.Resource, 0)

	for _, stateResource := range *resourcesFromState {
		// Ignore all resources other than policy attachment
		if stateResource.ResourceType() != resourceaws.AwsIamPolicyAttachmentResourceType {
			newStateResources = append(newStateResources, stateResource)
			continue
		}

		newStateResources = append(newStateResources, m.expand(stateResource)...)
	}

	var newRemoteResources = make([]*resource.Resource, 0)

	for _, remoteResource := range *remoteResources {
		// Ignore all resources other than policy attachment
		if remoteResource.ResourceType() != resourceaws.AwsIamPolicyAttachmentResourceType {
			newRemoteResources = append(newRemoteResources, remoteResource)
			continue
		}

		newRemoteResources = append(newRemoteResources, m.expand(remoteResource)...)
	}

	*resourcesFromState = newStateResources
	*remoteResources = newRemoteResources

	return nil
}

func (m IamPolicyAttachmentExpander) expand(policyAttachment *resource.Resource) []*resource.Resource {
	var newResources []*resource.Resource
	users := policyAttachment.Attrs.GetSlice("users")
	// we create one attachment per user
	for _, user := range users {
		user := user.(string)
		newAttachment := m.resourceFactory.CreateAbstractResource(
			resourceaws.AwsIamPolicyAttachmentResourceType,
			fmt.Sprintf("%s-%s", user, (*policyAttachment.Attrs)["policy_arn"]),
			map[string]interface{}{
				"policy_arn": *policyAttachment.Attrs.GetString("policy_arn"),
				"users":      []interface{}{user},
			},
		)
		newResources = append(newResources, newAttachment)
	}

	roles := policyAttachment.Attrs.GetSlice("roles")
	// we create one attachment per role
	for _, role := range roles {
		role := role.(string)
		newAttachment := m.resourceFactory.CreateAbstractResource(
			resourceaws.AwsIamPolicyAttachmentResourceType,
			fmt.Sprintf("%s-%s", role, (*policyAttachment.Attrs)["policy_arn"]),
			map[string]interface{}{
				"policy_arn": *policyAttachment.Attrs.GetString("policy_arn"),
				"roles":      []interface{}{role},
			},
		)
		newResources = append(newResources, newAttachment)
	}
	return newResources
}
