package region

import (
	"context"

	"github.com/samber/lo"
	"google.golang.org/protobuf/types/known/emptypb"

	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/entity"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/region"
	resourcepoolservice "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/resourcepool"
)

func NewServer(
	svc region.Service,
	resourcePoolSvc resourcepoolservice.Service,
) globalngv1.RegionServiceServer {
	return &server{
		Service:         svc,
		resourcePoolSvc: resourcePoolSvc,
	}
}

type server struct {
	region.Service

	resourcePoolSvc resourcepoolservice.Service
}

func (s *server) PlanResourcePoolCidr(
	ctx context.Context,
	req *globalngv1.PlanResourcePoolCidrRequest,
) (*globalngv1.PlanResourcePoolCidrResponse, error) {
	return s.resourcePoolSvc.PlanResourcePoolCidr(ctx, req)
}

func (s *server) ValidateResourcePoolCidr(
	ctx context.Context,
	req *globalngv1.ValidateResourcePoolCidrRequest,
) (*globalngv1.ValidateResourcePoolCidrResponse, error) {
	return s.resourcePoolSvc.ValidateResourcePoolCidr(ctx, req)
}

func (s *server) GetRegionByLogicalName(
	ctx context.Context,
	req *globalngv1.GetRegionByLogicalNameRequest,
) (*globalcommonv1.Region, error) {
	r, err := s.Service.GetRegionByLogicalName(ctx, req)
	if err != nil {
		return nil, err
	}
	return r.Region, nil
}

func (s *server) ListRegions(
	ctx context.Context,
	req *globalngv1.ListRegionsRequest,
) (*globalngv1.ListRegionsResponse, error) {
	regions, err := s.Service.ListRegions(ctx, req)
	if err != nil {
		return nil, err
	}
	return &globalngv1.ListRegionsResponse{
		Regions: lo.Map(regions, func(region *entity.Region, _ int) *globalcommonv1.Region {
			return region.Region
		}),
	}, nil
}

func (s *server) ListCloudProviders(
	ctx context.Context,
	req *globalngv1.ListCloudProvidersRequest,
) (*globalngv1.ListCloudProvidersResponse, error) {
	cloudProviders, err := s.Service.ListCloudProviders(ctx, req)
	if err != nil {
		return nil, err
	}
	outputs := lo.Map(cloudProviders, func(cp *entity.CloudProvider, _ int) *globalcommonv1.CloudProvider {
		return cp.CloudProvider
	})
	return &globalngv1.ListCloudProvidersResponse{
		CloudProviders: outputs,
	}, nil
}

func (s *server) RegisterCloudProvider(
	ctx context.Context,
	req *globalngv1.RegisterCloudProviderRequest,
) (*globalcommonv1.CloudProvider, error) {
	cp, err := s.Service.RegisterCloudProvider(ctx, req)
	if err != nil {
		return nil, err
	}
	return cp.CloudProvider, nil
}

func (s *server) RegisterRegion(
	ctx context.Context,
	req *globalngv1.RegisterRegionRequest,
) (*globalcommonv1.Region, error) {
	r, err := s.Service.RegisterRegion(ctx, req)
	if err != nil {
		return nil, err
	}
	return r.Region, nil
}

func (s *server) UpdateRegion(
	ctx context.Context,
	req *globalngv1.UpdateRegionRequest,
) (*globalcommonv1.Region, error) {
	r, err := s.Service.UpdateRegion(ctx, req)
	if err != nil {
		return nil, err
	}
	return r.Region, nil
}

func (s *server) DeleteRegion(
	ctx context.Context,
	req *globalngv1.DeleteRegionRequest,
) (*emptypb.Empty, error) {
	_, err := s.Service.DeleteRegion(ctx, req)
	if err != nil {
		return nil, err
	}
	return &emptypb.Empty{}, nil
}

func (s *server) GetRegionByClusterId(
	ctx context.Context,
	req *globalngv1.GetRegionByClusterIdRequest,
) (*globalcommonv1.Region, error) {
	r, err := s.Service.GetRegionByClusterId(ctx, req)
	if err != nil {
		return nil, err
	}
	return r.Region, nil
}

func (s *server) SelectRegionByOrgId(
	ctx context.Context,
	req *globalngv1.SelectRegionByOrgIdRequest,
) (*globalcommonv1.Region, error) {
	r, err := s.Service.SelectRegionByOrgId(ctx, req)
	if err != nil {
		return nil, err
	}
	return r.Region, nil
}

func (s *server) UpdateRegionOpsAuditLogSetting(
	ctx context.Context,
	request *globalngv1.UpdateRegionOpsAuditLogSettingRequest,
) (*globalngv1.UpdateRegionOpsAuditLogSettingResponse, error) {
	r, err := s.Service.UpdateRegionOpsAuditLogSetting(ctx, request)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) RegisterRegionProviderIdentity(ctx context.Context,
	request *globalngv1.RegisterRegionProviderIdentityRequest,
) (*globalngv1.RegionProviderIdentity, error) {
	r, err := s.Service.RegisterRegionProviderIdentity(ctx, request)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) ListRegionProviderIdentities(ctx context.Context,
	request *globalngv1.ListRegionProviderIdentitiesRequest,
) (*globalngv1.ListRegionProviderIdentitiesResponse, error) {
	r, err := s.Service.ListRegionProviderIdentities(ctx, request)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) ListRegionCapacities(
	ctx context.Context,
	req *globalngv1.ListRegionCapacitiesRequest,
) (*globalngv1.ListRegionCapacitiesResponse, error) {
	r, err := s.Service.ListRegionCapacities(ctx, req)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) ListByocVcpuPools(
	ctx context.Context,
	req *globalngv1.ListByocVcpuPoolsRequest,
) (*globalngv1.ListByocVcpuPoolsResponse, error) {
	r, err := s.Service.ListByocVcpuPools(ctx, req)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) GetByocSharedComponentScaleConstraints(
	ctx context.Context,
	req *globalngv1.GetByocSharedComponentScaleConstraintsRequest,
) (*globalngv1.ByocSharedComponentScaleConstraints, error) {
	r, err := s.Service.GetByocSharedComponentScaleConstraints(ctx, req)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) ScaleByocSharedComponents(
	ctx context.Context,
	req *globalngv1.ScaleByocSharedComponentsRequest,
) (*globalngv1.ScaleByocSharedComponentsResponse, error) {
	r, err := s.Service.ScaleByocSharedComponents(ctx, req)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *server) ListNodeSpecs(
	ctx context.Context,
	req *globalngv1.ListNodeSpecsRequest,
) (*globalngv1.ListNodeSpecsResponse, error) {
	return s.Service.ListNodeSpecs(ctx, req)
}
