package vpc

import (
	"context"

	"google.golang.org/protobuf/types/known/emptypb"

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

func (s *server) ListVpcs(
	ctx context.Context,
	req *globaldedicatedv1.ListVpcsRequest,
) (*globaldedicatedv1.ListVpcsResponse, error) {
	resp, err := s.vpcService.ListVpcs(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *server) DeleteVpc(ctx context.Context, req *globaldedicatedv1.DeleteVpcRequest) (*emptypb.Empty, error) {
	err := s.vpcService.DeleteVpc(ctx, req)
	if err != nil {
		return nil, err
	}

	return &emptypb.Empty{}, nil
}

func (s *server) CreateCidr(
	ctx context.Context,
	request *globaldedicatedv1.CreateCidrRequest,
) (*globaldedicatedv1.CreateCidrResponse, error) {
	resp := &globaldedicatedv1.CreateCidrResponse{}

	if request.CloudProviderName == "" {
		return resp, bizerr.New(bizerr.ErrCodeParams, "cloud provider name is unspecified")
	}
	if request.RegionName == "" {
		return resp, bizerr.New(bizerr.ErrCodeParams, "region name is unspecified")
	}
	if request.Cidr == "" {
		return resp, bizerr.New(bizerr.ErrCodeParams, "CIDR is unspecified")
	}

	cidr, validateOnlyResponse, err := s.vpcService.CreateCidr(ctx, &globaldedicatedv1.CreateCidrRequest{
		ProjectId:         request.ProjectId,
		CloudProviderName: request.CloudProviderName,
		RegionName:        request.RegionName,
		Cidr:              request.Cidr,
		ValidateOnly:      request.ValidateOnly,
	})
	if err != nil {
		return resp, bizerr.WrapError(err, "create CIDR")
	}

	if cidr != nil {
		resp.Id = cidr.ID
	}
	if validateOnlyResponse != nil {
		resp.Overlaps = buildCidrOverlaps(validateOnlyResponse.Overlaps)
		resp.MaxNodeIp = validateOnlyResponse.MaxNodeIP
	}

	return resp, nil
}

func (s *server) QueryCidrs(
	ctx context.Context,
	request *globaldedicatedv1.QueryCidrsRequest,
) (*globaldedicatedv1.QueryCidrsResponse, error) {
	resp := &globaldedicatedv1.QueryCidrsResponse{}

	cidrs, err := s.vpcService.QueryCidrs(ctx, request)
	if err != nil {
		return resp, err
	}
	resp.Items = cidrs

	return resp, nil
}

func (s *server) UpdateCidr(
	ctx context.Context,
	request *globaldedicatedv1.UpdateCidrRequest,
) (*globaldedicatedv1.UpdateCidrResponse, error) {
	resp := &globaldedicatedv1.UpdateCidrResponse{}

	if request.Cidr == "" {
		return resp, bizerr.New(bizerr.ErrCodeParams, "CIDR is unspecified")
	}

	params := &vpc.UpdateCidrParams{
		CidrID:       request.Id,
		ProjectID:    request.ProjectId,
		CIDR:         request.Cidr,
		ValidateOnly: request.ValidateOnly,
	}
	validateOnlyResponse, err := s.updateCidrSvc.Execute(ctx, params)
	if err != nil {
		return resp, bizerr.WrapError(err, "update CIDR")
	}

	if validateOnlyResponse != nil {
		resp.MaxNodeIp = validateOnlyResponse.MaxNodeIP
		resp.Overlaps = buildCidrOverlaps(validateOnlyResponse.Overlaps)
	}

	return resp, nil
}

func (s *server) DeleteCidr(ctx context.Context, request *globaldedicatedv1.DeleteCidrRequest) (*emptypb.Empty, error) {
	if err := s.deleteCidrSvc.Execute(ctx, request.ProjectId, request.Id); err != nil {
		return nil, bizerr.WrapError(err, "delete CIDR")
	}

	return &emptypb.Empty{}, nil
}

func (s *server) GetDefaultCidr(
	ctx context.Context,
	request *globaldedicatedv1.GetDefaultCidrRequest,
) (*globaldedicatedv1.GetDefaultCidrResponse, error) {
	resp := &globaldedicatedv1.GetDefaultCidrResponse{}

	defaultCidr, err := s.vpcService.GetDefaultCidr(ctx, request)
	if err != nil {
		return resp, err
	}

	resp.DefaultCidr = defaultCidr

	return resp, nil
}

func buildCidrOverlaps(overlaps []*vpc.Overlap) []*globaldedicatedv1.CidrOverlap {
	var out []*globaldedicatedv1.CidrOverlap
	for _, overlap := range overlaps {
		out = append(out, cidrOverlapToPb(overlap))
	}
	return out
}

func cidrOverlapToPb(overlap *vpc.Overlap) *globaldedicatedv1.CidrOverlap {
	if overlap == nil {
		return nil
	}
	var regions []*globaldedicatedv1.CidrOverlap_CloudRegion
	for _, enRegion := range overlap.Regions {
		regions = append(regions, &globaldedicatedv1.CidrOverlap_CloudRegion{
			Name:              enRegion.Name.String(),
			DisplayName:       enRegion.DisplayName,
			CloudProviderName: enRegion.CloudProviderName.String(),
		})
	}

	return &globaldedicatedv1.CidrOverlap{
		Regions:   regions,
		ProjectId: overlap.ProjectID,
	}
}
