package region

import (
	"context"
	"errors"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *service) RegisterCloudProvider(
	ctx context.Context,
	req *globaldedicatedv1.RegisterCloudProviderRequest,
) (*entity.CloudProvider, bizerr.BizError) {
	if req.GetCloudProvider() == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cloud provider is required")
	}

	cp := req.GetCloudProvider()

	if err := s.transaction.Transaction(ctx, func(ctx context.Context) error {
		// check if cloud provider already exists
		_, err := s.repo.GetCloudProviderById(ctx, cp.GetId(), 0)
		if err == nil {
			return bizerr.New(bizerr.ErrCodeRecordExist, "cloud provider %s already exists", cp.GetId())
		}

		// if error code is not ErrCodeParam, means provider not exists
		var be bizerr.BizError
		ok := errors.As(err, &be)
		if ok && be.ErrCode() != bizerr.ErrCodeParams {
			return err
		}

		// save cloud provider
		err = s.repo.SaveCloudProvider(ctx, cp)
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return nil, bizerr.WrapError(err, "register cloud provider failed")
	}

	return cp, nil
}

func (s *service) ListCloudProviders(
	ctx context.Context,
	req *globaldedicatedv1.ListCloudProvidersRequest,
) ([]*entity.CloudProvider, bizerr.BizError) {
	ps, err := s.repo.ListAllCloudProviders(ctx, req.GetOrganizationId())
	if err != nil {
		return nil, err
	}

	if len(ps) == 0 {
		return []*entity.CloudProvider{}, nil
	}

	rps := make([]*entity.CloudProvider, 0)
	for _, p := range ps {
		if req.GetOrganizationId() != 0 {
			rs := make([]*entity.Region, 0)
			// organization is set, check if the region is open to the tenant
			for _, r := range p.GetRegions() {
				if entity.IsRegionOpenToTenant(r, req.GetOrganizationId()) {
					rs = append(rs, r)
				} else {
					tilog.Warn(ctx, "region is not open to tenant", zap.String("region", r.GetId().String()))
				}
			}
			// if has regions, add to response
			if len(rs) > 0 {
				p.Regions = rs
				rps = append(rps, p)
			}
		} else {
			// public provider or organization is not set, add all regions
			rps = append(rps, p)
		}
	}

	return rps, nil
}
