package regionserver

import (
	"context"
	"fmt"
	"net/http"

	"github.com/go-resty/resty/v2"
	regionaldedicatedv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"

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

func (s *regionServerCliImpl) CreateVpc(
	ctx context.Context,
	region *entity.Region,
	req *regionaldedicatedv1.CreateVpcRequest,
) (*regionaldedicatedv1.Vpc, bizerr.BizError) {
	body, err := marshalOptions.Marshal(req)
	if err != nil {
		return nil, bizerr.New(bizerr.ErrCodeJsonMarshal, "%s", err.Error())
	}
	resp, berr := s.callRegion(
		ctx,
		region,
		http.MethodPost,
		operationMap["CreateVpc"],
		func(request *resty.Request) *resty.Request {
			request.SetBody(body)
			return request
		},
	)
	if berr != nil {
		return nil, berr
	}

	var out regionaldedicatedv1.Vpc
	if err := unmarshalOptions.Unmarshal(resp.Body(), &out); err != nil {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "%s", err.Error())
	}

	return &out, nil
}

func (s *regionServerCliImpl) GetVpc(
	ctx context.Context,
	region *entity.Region,
	req *regionaldedicatedv1.GetVpcRequest,
) (*regionaldedicatedv1.Vpc, bizerr.BizError) {
	resp, err := s.callRegion(
		ctx,
		region,
		http.MethodGet,
		operationMap["GetVpc"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(vpcIdPathParameter, req.GetVpcId())
			return request
		},
	)
	if err != nil {
		return nil, err
	}

	var out regionaldedicatedv1.Vpc
	if err := unmarshalOptions.Unmarshal(resp.Body(), &out); err != nil {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "%s", err.Error())
	}

	return &out, nil
}

func (s *regionServerCliImpl) DeleteVpc(
	ctx context.Context,
	region *entity.Region,
	req *regionaldedicatedv1.DeleteVpcRequest,
) bizerr.BizError {
	vpc, bizErr := s.GetVpc(ctx, region, &regionaldedicatedv1.GetVpcRequest{VpcId: req.GetVpcId()})
	if bizErr != nil {
		return bizErr
	}
	expectRequest := &metadata.ExpectRequest[string]{
		TenantId:   "", // fill later
		ProjectId:  "", // fill later
		ClusterId:  "", // leave it empty
		ResourceId: vpc.VpcId,
	}
	if len(vpc.TenantIds) > 0 {
		expectRequest.TenantId = vpc.TenantIds[0]
	}
	if len(vpc.ProjectIds) > 0 {
		expectRequest.ProjectId = vpc.ProjectIds[0]
	}
	if err := metadata.Validate(ctx, expectRequest); err != nil {
		return bizerr.WrapError(err, "validate failed")
	}

	_, err := s.callRegion(
		ctx,
		region,
		http.MethodDelete,
		operationMap["DeleteVpc"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(vpcIdPathParameter, req.GetVpcId())
			return request
		},
	)
	if err != nil {
		return err
	}

	return nil
}

func (s *regionServerCliImpl) ListVpcs(
	ctx context.Context,
	region *entity.Region,
	req *regionaldedicatedv1.ListVpcsRequest,
) (*regionaldedicatedv1.ListVpcsResponse, bizerr.BizError) {
	resp, err := s.callRegion(
		ctx,
		region,
		http.MethodGet,
		operationMap["ListVpcs"],
		func(request *resty.Request) *resty.Request {
			queryParams, err := protobufStructToMap(req)
			if err != nil {
				return nil
			}

			for key, value := range queryParams {
				switch val := value.(type) {
				case []any:
					request.SetQueryParamsFromValues(convertArrayFieldValueToValues(key, val))
				default:
					request.SetQueryParam(key, fmt.Sprintf("%v", value))
				}
			}
			return request
		},
	)
	if err != nil {
		return nil, err
	}

	var out regionaldedicatedv1.ListVpcsResponse
	if err := unmarshalOptions.Unmarshal(resp.Body(), &out); err != nil {
		return nil, bizerr.New(bizerr.ErrCodeUnknown, "%s", err.Error())
	}

	return &out, nil
}

func (s *regionServerCliImpl) AddSecondaryCidr(
	ctx context.Context,
	region *entity.Region,
	req *regionaldedicatedv1.AddSecondaryCidrRequest,
) (*regionaldedicatedv1.Vpc, bizerr.BizError) {
	body, err := marshalOptions.Marshal(req)
	if err != nil {
		return nil, bizerr.New(bizerr.ErrCodeJsonMarshal, "%s", err.Error())
	}
	resp, berr := s.callRegion(
		ctx,
		region,
		http.MethodPost,
		operationMap["AddSecondaryCidr"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(vpcIdPathParameter, req.GetVpcId())
			request.SetBody(body)
			return request
		},
	)
	if berr != nil {
		return nil, berr
	}

	var out regionaldedicatedv1.Vpc
	if err := unmarshalOptions.Unmarshal(resp.Body(), &out); err != nil {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "%s", err.Error())
	}

	return &out, nil
}
