package impl

import (
	"context"

	appconfig "github.com/tidbcloud/dataflow-service/app/config"
	"github.com/tidbcloud/dataflow-service/app/models/bucket"
	"github.com/tidbcloud/dataflow-service/app/models/domain"
	bizerr_wrapper "github.com/tidbcloud/dataflow-service/pkg/bizerr-wrapper"
	"github.com/tidbcloud/dataflow-service/pkg/log"
	"github.com/tidbcloud/pkgv2/bizerr"
)

type bucketModelProxy struct {
	bucketModelMap map[domain.InfraProviderType]bucket.BucketModelV2
}

func NewBucketModelProxy(
	eksBucketModel bucket.BucketModelV2,
	gkeBucketModel bucket.BucketModelV2,
	aksBucketModel bucket.BucketModelV2,
) bucket.BucketModelV2 {
	proxy := &bucketModelProxy{}
	proxy.bucketModelMap = make(map[domain.InfraProviderType]bucket.BucketModelV2)
	proxy.bucketModelMap[domain.InfraProviderTypeEKS] = eksBucketModel
	proxy.bucketModelMap[domain.InfraProviderTypeAWS] = eksBucketModel
	proxy.bucketModelMap[domain.InfraProviderTypeGKE] = gkeBucketModel
	proxy.bucketModelMap[domain.InfraProviderTypeGCP] = gkeBucketModel
	proxy.bucketModelMap[domain.InfraProviderTypeAKS] = aksBucketModel
	proxy.bucketModelMap[domain.InfraProviderTypeAzure] = aksBucketModel
	return proxy
}

func (p *bucketModelProxy) getModel(
	ctx context.Context, providerType *domain.InfraProviderType,
) (bucket.BucketModelV2, bizerr.BizError) {
	logger := log.GetLogger(ctx)
	if providerType == nil {
		logger.Warn("provider type is nil")
		return nil, bizerr_wrapper.NewInternalErr(appconfig.ErrInternalError)
	}
	model, ok := p.bucketModelMap[*providerType]
	if !ok {
		logger.Warn("get bucket model failed")
		return nil, bizerr_wrapper.NewInternalErr(appconfig.ErrInternalError)
	}
	return model, nil
}

func (p *bucketModelProxy) CreateBucket(
	ctx context.Context, req *domain.CreateBucketReqV2,
) (*domain.CreateBucketRespV2, bizerr.BizError) {
	ctx = log.WithTraceID(ctx)
	model, err := p.getModel(ctx, req.InfraCloudProvider)
	if err != nil {
		return nil, err
	}
	return model.CreateBucket(ctx, req)
}

func (p *bucketModelProxy) DeleteBucket(
	ctx context.Context, req *domain.DeleteBucketReqV2,
) (*domain.DeleteBucketRespV2, bizerr.BizError) {
	ctx = log.WithTraceID(ctx)
	model, err := p.getModel(ctx, req.InfraCloudProvider)
	if err != nil {
		return nil, err
	}
	return model.DeleteBucket(ctx, req)
}

func (p *bucketModelProxy) GetBucket(
	ctx context.Context, req *domain.GetBucketReq,
) (*domain.GetBucketResp, bizerr.BizError) {
	ctx = log.WithTraceID(ctx)
	model, err := p.getModel(ctx, req.InfraCloudProvider)
	if err != nil {
		return nil, err
	}
	return model.GetBucket(ctx, req)
}

func (p *bucketModelProxy) GrantAccessToBucket(
	ctx context.Context, req *domain.GrantAccessToBucketReq,
) (*domain.GrantAccessToBucketResp, bizerr.BizError) {
	ctx = log.WithTraceID(ctx)
	model, err := p.getModel(ctx, req.InfraCloudProvider)
	if err != nil {
		return nil, err
	}
	return model.GrantAccessToBucket(ctx, req)
}

func (p *bucketModelProxy) RevokeAccessToBucket(
	ctx context.Context, req *domain.RevokeAccessToBucketReq,
) (*domain.RevokeAccessToBucketResp, bizerr.BizError) {
	ctx = log.WithTraceID(ctx)
	model, err := p.getModel(ctx, req.InfraCloudProvider)
	if err != nil {
		return nil, err
	}
	return model.RevokeAccessToBucket(ctx, req)
}
