package aws

import (
	awssdk "github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/autoscaling"
	"github.com/aws/aws-sdk-go-v2/service/cloudformation"
	"github.com/aws/aws-sdk-go-v2/service/costexplorer"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
	"github.com/aws/aws-sdk-go-v2/service/ec2"
	"github.com/aws/aws-sdk-go-v2/service/eks"
	"github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing"
	"github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
	"github.com/aws/aws-sdk-go-v2/service/iam"
	"github.com/aws/aws-sdk-go-v2/service/lambda"
	"github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi"
	"github.com/aws/aws-sdk-go-v2/service/route53"
	"github.com/aws/aws-sdk-go-v2/service/s3"
	"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
	"github.com/aws/aws-sdk-go-v2/service/sns"
	"github.com/aws/aws-sdk-go-v2/service/sqs"
	"github.com/aws/aws-sdk-go-v2/service/sts"
)

func newSTSClient(cfg *awssdk.Config) STSAPI {
	return sts.NewFromConfig(*cfg)
}

// NewSTSClient exposes the shared STS client construction for lifecycle code.
func NewSTSClient(cfg *awssdk.Config) STSAPI {
	return newSTSClient(cfg)
}

// NewTaggingClient exposes the shared Resource Groups Tagging API client used
// by cp9 purge broad discovery.
func NewTaggingClient(cfg *awssdk.Config) TaggingAPI {
	return resourcegroupstaggingapi.NewFromConfig(*cfg)
}

// NewIAMInventoryClient exposes the IAM client used to snapshot an account's
// IAM. It satisfies both the listing and the tag-reading surface the snapshot
// needs.
func NewIAMInventoryClient(cfg *awssdk.Config) *iam.Client {
	return iam.NewFromConfig(*cfg)
}

// NewAutoScalingClient exposes the Auto Scaling client used for broad-mode
// managed-scope discovery. Tagged groups are missing from the regional tag index.
func NewAutoScalingClient(cfg *awssdk.Config) AutoScalingGraphAPI {
	return autoscaling.NewFromConfig(*cfg)
}

// NewInventoryEC2Client exposes the read-only EC2 client used by cp9 inventory.
func NewInventoryEC2Client(cfg *awssdk.Config) InventoryEC2API {
	return ec2.NewFromConfig(*cfg)
}

// NewInventoryEKSClient exposes the read-only EKS client used by cp9 inventory.
func NewInventoryEKSClient(cfg *awssdk.Config) InventoryEKSAPI {
	return eks.NewFromConfig(*cfg)
}

// NewClients creates all AWS service clients from a shared config.
func NewClients(cfg *awssdk.Config) (*ResourceTracker, *ResourceCleaner, *SessionCostReporter) {
	iamClient := iam.NewFromConfig(*cfg)
	ec2Client := ec2.NewFromConfig(*cfg)
	eksClient := eks.NewFromConfig(*cfg)
	elbClient := elasticloadbalancing.NewFromConfig(*cfg)
	elbv2Client := elasticloadbalancingv2.NewFromConfig(*cfg)
	cfnClient := cloudformation.NewFromConfig(*cfg)
	tracker := NewTrackerWithIAM(resourcegroupstaggingapi.NewFromConfig(*cfg), iamClient, cfg.Region).
		WithEC2ResourceGraph(ec2Client).
		WithEKSResourceGraph(eksClient).
		WithELBResourceGraph(elbv2Client).
		WithClassicELBResourceGraph(elbClient).
		WithAutoScalingGraph(autoscaling.NewFromConfig(*cfg))

	cleaner := &ResourceCleaner{
		CloudFormation: cfnClient,
		EKS:            eksClient,
		EC2:            ec2Client,
		PlacementGroup: ec2Client,
		ELBV2:          elbv2Client,
		IAM:            iamClient,
		SQS:            sqs.NewFromConfig(*cfg),
		S3:             s3.NewFromConfig(*cfg),
		DynamoDB:       dynamodb.NewFromConfig(*cfg),
		SNS:            sns.NewFromConfig(*cfg),
		Lambda:         lambda.NewFromConfig(*cfg),
		SecretsManager: secretsmanager.NewFromConfig(*cfg),
		Route53:        route53.NewFromConfig(*cfg),
	}

	costReporter := NewCostReporter(costexplorer.NewFromConfig(*cfg))

	return tracker, cleaner, costReporter
}
