package stashing

import (
	"fmt"

	"github.com/pingcap/log"
	"github.com/tidbcloud/serverless-service/internal/config"
	aws2 "github.com/tidbcloud/serverless-service/internal/infra/aws"
	"go.uber.org/zap"
)

type StashingAreaProvider struct {
	stashingAreas map[string]*StashingArea
}

func NewStashingAreaProvider(
	preSignerProvider *aws2.PresignerProvider,
	s3ClientProvider *aws2.S3ClientProvider,
) *StashingAreaProvider {
	stashingAreas := make(map[string]*StashingArea)
	for _, regionConfig := range config.Global().WorkerConfig.RegionalConfig {
		if !config.HasS3CompatibleStashing(regionConfig.Provider) {
			continue
		}
		region := regionConfig.Region
		key := getStashingAreaKey(regionConfig.Provider, region)
		preSignerClient, err := preSignerProvider.GetPresignerClient(regionConfig.Provider, region)
		if err != nil {
			log.Warn("skip creating stashing area, presigner not found",
				zap.String("provider", regionConfig.Provider),
				zap.String("region", region),
				zap.Error(err))
			continue
		}
		s3Client, err := s3ClientProvider.GetS3Client(regionConfig.Provider, region)
		if err != nil {
			log.Warn("skip creating stashing area, s3 client not found",
				zap.String("provider", regionConfig.Provider),
				zap.String("region", region),
				zap.Error(err))
			continue
		}
		switch regionConfig.Provider {
		case config.ProviderAWS:
			stashingAreas[key] = &StashingArea{
				preSignerClient: preSignerClient,
				s3Client:        s3Client,
				Region:          region,
			}
		case config.ProviderAliCloud:
			stashingAreas[key] = &StashingArea{
				preSignerClient: preSignerClient,
				s3Client:        s3Client,
				Region:          region,
				Endpoint:        fmt.Sprintf("https://oss-%s.aliyuncs.com", region),
				AccessKeyID:     config.Global().OssConfig.AccessKeyID,
				SecretAccessKey: config.Global().OssConfig.SecretAccessKey,
			}
		}
	}

	return &StashingAreaProvider{
		stashingAreas: stashingAreas,
	}
}

// GetStashingArea returns a new StashingArea with the given region. The region should be the same as the cluster region
// so that the traffic cost is free.
func (s *StashingAreaProvider) GetStashingArea(provider, region string) (*StashingArea, error) {
	key := getStashingAreaKey(provider, region)
	if s.stashingAreas[key] == nil {
		return nil, fmt.Errorf("stashing area for region %s and provider %s not found", region, provider)
	}
	return s.stashingAreas[key], nil
}

func getStashingAreaKey(provider, region string) string {
	return fmt.Sprintf("%s/%s", provider, region)
}
