package br

import (
	"context"
	"strings"

	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *serviceImpl) TestClassicBackupAccess(
	ctx context.Context,
	req *globalngv1.TestClassicBackupAccessRequest,
) (*globalngv1.TestClassicBackupAccessResponse, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.TestClassicBackupAccess")
	defer span.End()
	return doTestClassicBackupAccess(ctx, req, s.regionRepo, s.regionalCli)
}

func doTestClassicBackupAccess(
	ctx context.Context,
	req *globalngv1.TestClassicBackupAccessRequest,
	regionRepo region.Repo,
	regionalCli regionalserver.Client,
) (*globalngv1.TestClassicBackupAccessResponse, bizerr.BizError) {
	theRegion, berr := selectRegionForTestClassicBackupAccess(ctx, req, regionRepo)
	if berr != nil {
		return nil, berr.Chain("failed to select region for test classic backup access")
	}

	cloudProvider := strings.ToLower(req.GetClassicBackupStorage().GetCloudProvider().String())
	resp, berr := regionalCli.TestClassicBackupAccess(ctx, theRegion, &clusterngv1beta.TestClassicBackupAccessRequest{
		CloudProvider:   cloudProvider,
		BucketUri:       req.GetClassicBackupStorage().GetBucketUri(),
		AccessKeyId:     req.GetClassicBackupStorage().GetAuth().GetAccessKeyId(),
		AccessKeySecret: req.GetClassicBackupStorage().GetAuth().GetAccessKeySecret(),
		Region:          req.GetClassicBackupStorage().GetRegion(),
	})
	if berr != nil {
		return nil, berr.Chain("failed to test classic backup access")
	}

	return &globalngv1.TestClassicBackupAccessResponse{
		Status:        globalngv1.TestClassicBackupAccessResponse_Status(resp.GetStatus()),
		Message:       resp.GetMessage(),
		CloudProvider: req.GetClassicBackupStorage().GetCloudProvider(),
		Region:        resp.GetRegion(),
		Version:       resp.GetVersion(),
		BackupTime:    resp.GetBackupTime(),
		DataSizeBytes: resp.GetDataSizeBytes(),
	}, nil
}

func selectRegionForTestClassicBackupAccess(
	ctx context.Context,
	req *globalngv1.TestClassicBackupAccessRequest,
	regionRepo region.Repo,
) (*entity.Region, bizerr.BizError) {
	regions, berr := regionRepo.ListRegions(ctx, region.Filter{
		CloudProvider: req.GetClassicBackupStorage().GetCloudProvider(),
		ServicePlan:   req.GetServicePlan(),
		TenantId:      req.GetOrganizationId(),
		State:         globalcommonv1.Region_ACTIVE.String(),
	})
	if berr != nil {
		return nil, berr.Chain("failed to list regions")
	}

	if len(regions) == 0 {
		return nil, bizerr.New(
			bizerr.GeneralInternalErrorCode,
			"no active region found for tenant %d and service plan %s",
			req.GetOrganizationId(),
			req.GetServicePlan().String(),
		)
	}

	// find the region same as the backup storage region
	for _, it := range regions {
		if strings.EqualFold(it.RegionName, req.GetClassicBackupStorage().GetRegion()) {
			tilog.Info(ctx, "found region for test classic backup access", zap.String("region", it.RegionName))
			return it, nil
		}
	}

	tilog.Info(ctx, "no region found for test classic backup access, use the first region", zap.Any("first region", regions[0]))
	return regions[0], nil
}
