package encryptionkey

import (
	"context"

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

	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

const cloudResourcesNotReadyMessage = "Cloud resources are not ready. Please contact Support."

func cloudResourcesNotReadyError(err bizerr.BizError, operation string) bizerr.BizError {
	if err == nil {
		return nil
	}
	return err.
		OverwriteMessage(cloudResourcesNotReadyMessage).
		Chain("%s", operation)
}

func physicalClusterNotReadyError(err bizerr.BizError, operation string) bizerr.BizError {
	if err == nil {
		return nil
	}
	return err.
		OverwriteCode(bizerr.ErrCodePhysicalClusterNotReady).
		OverwriteMessage(cloudResourcesNotReadyMessage).
		Chain("physical cluster is not ready").
		Chain("%s", operation)
}

func (s *service) kmsVerifyFailureError(
	ctx context.Context,
	cloudRegion *entity.Region,
	target kmsCheckTarget,
	err bizerr.BizError,
	operation string,
) bizerr.BizError {
	if err == nil {
		return nil
	}
	if err.ErrCode() == bizerr.ErrCodeRegionalAPI || err.ErrCode() == bizerr.ErrCodeRecordNotFound {
		// Use a fresh shared-pool read only after a failed KMS check; this avoids
		// classifying regional outages as physical-cluster-not-ready.
		ready, readyErr := s.physicalClusterReadyForKMS(ctx, cloudRegion, target)
		if readyErr != nil {
			tilog.Warn(ctx, "failed to check physical cluster readiness for kms verify",
				zap.String("shared_pool_id", target.sharedPoolID),
				zap.Error(readyErr))
			return err.Chain("%s", operation)
		}
		if !ready {
			return physicalClusterNotReadyError(err, operation)
		}
	}
	return err.Chain("%s", operation)
}

func (s *service) physicalClusterReadyForKMS(
	ctx context.Context,
	cloudRegion *entity.Region,
	target kmsCheckTarget,
) (bool, bizerr.BizError) {
	if target.sharedPoolID == "" || target.sharedPoolID == "0" {
		return false, nil
	}

	sharedPool, err := s.nextgenCli.GetSharedPool(ctx, cloudRegion, &clusterngv1beta.GetSharedPoolRequest{
		SharedPoolId: target.sharedPoolID,
	})
	if err != nil {
		if err.ErrCode() == bizerr.ErrCodeRecordNotFound {
			return false, nil
		}
		return false, err
	}
	if sharedPool == nil {
		return false, bizerr.New(bizerr.ErrCodeRegionalAPI, "get shared pool returned empty response")
	}
	return sharedPool.GetPhase() == clusterngv1beta.SharedPool_AVAILABLE, nil
}
