package aws

import (
	"context"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/pingcap/errors"
	service_config "github.com/tidbcloud/dataflow-service/internal/config"
	"net/http"
	"sync"
	"time"
)

// FIXME: duplicated code, should be refactored
type AWSRoute53ClientProxy interface {
	GetClient(ctx context.Context, req *GetAWSClientReq) (*route53.Route53, error)
}

type awsRoute53ClientProxy struct {
	lock sync.Mutex

	// k : accountID-region, v : route53 client
	clientM map[string]*route53.Route53
}

func NewAWSRoute53ClientProxy() AWSRoute53ClientProxy {
	return &awsRoute53ClientProxy{clientM: map[string]*route53.Route53{}}
}

func (b *awsRoute53ClientProxy) GetClient(ctx context.Context, req *GetAWSClientReq) (*route53.Route53, error) {
	b.lock.Lock()
	defer b.lock.Unlock()

	key := fmt.Sprintf("%s-%s", req.AccountID, req.Region)
	if client, ok := b.clientM[key]; ok {
		return client, nil
	}
	awsSessionOpts := session.Options{
		Config: *aws.NewConfig().WithCredentialsChainVerboseErrors(true).WithRegion(req.Region),
	}
	ses, err := session.NewSessionWithOptions(awsSessionOpts)
	if err != nil {
		return nil, errors.AddStack(err)
	}
	roleARN := req.GenerateDataflowRoleArn()
	creds := stscreds.NewCredentials(ses, roleARN, func(p *stscreds.AssumeRoleProvider) {
		p.RoleARN = roleARN
	})

	client := route53.New(ses, &aws.Config{
		Credentials: creds,
		HTTPClient: &http.Client{
			Timeout: time.Duration(service_config.Global().AwsConfig.S3SDKRequestTimeout) * time.Second,
		},
	})
	b.clientM[key] = client
	return client, nil
}
