package regionserver

import (
	"context"
	"net/http"

	"github.com/go-resty/resty/v2"
	clusteragentv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-agent/v1"
	regionalcommon "github.com/tidbcloud/infra-provider/api/tidbcloud/common"

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

func (s *regionServerCliImpl) ExecuteClusterAgentCommand(
	ctx context.Context,
	region *entity.Region,
	clusterId string,
	req *clusteragentv1.ExecuteCommandReq,
) (*clusteragentv1.ExecuteCommandResp, 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["ExecuteClusterAgentCommand"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(clusterIdParameter, clusterId)
			request.SetBody(body)
			return request
		},
	)
	if berr != nil {
		return nil, berr
	}

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

func (s *regionServerCliImpl) PauseClusterTc(
	ctx context.Context,
	region *entity.Region,
	clusterId string,
) bizerr.BizError {
	req := &clusteragentv1.PauseTCReq{
		ClusterId: clusterId,
		All:       true,
	}
	body, err := marshalOptions.Marshal(req)
	if err != nil {
		return bizerr.New(bizerr.ErrCodeJsonMarshal, "%s", err.Error())
	}
	resp, berr := s.callRegion(
		ctx,
		region,
		http.MethodPost,
		operationMap["PauseClusterTc"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(clusterIdParameter, clusterId)
			request.SetBody(body)
			return request
		},
	)
	if berr != nil {
		return bizerr.WrapError(berr, "failed to pause cluster tc")
	}
	if resp.StatusCode() != http.StatusOK {
		return bizerr.New(bizerr.ErrCodeRegionalAPI, "failed to pause cluster tc, status code: %d", resp.StatusCode())
	}
	return nil
}

func (s *regionServerCliImpl) DeleteClusterAstsAndResumeTc(
	ctx context.Context,
	region *entity.Region,
	clusterId string,
) bizerr.BizError {
	componentTypesToDeleted := []regionalcommon.ComponentType{
		regionalcommon.ComponentType_TIKV, regionalcommon.ComponentType_TIDB,
		regionalcommon.ComponentType_TIFLASH, regionalcommon.ComponentType_TIFLASH_LEARNER,
		regionalcommon.ComponentType_PD, regionalcommon.ComponentType_TIPROXY,
	}
	req := &clusteragentv1.DeleteASTSAndResumeTCReq{
		ClusterId:      clusterId,
		ComponentTypes: componentTypesToDeleted,
	}
	body, err := marshalOptions.Marshal(req)
	if err != nil {
		return bizerr.New(bizerr.ErrCodeJsonMarshal, "%s", err.Error())
	}
	resp, berr := s.callRegion(
		ctx,
		region,
		http.MethodPost,
		operationMap["DeleteClusterAstsAndResumeTc"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(clusterIdParameter, clusterId)
			request.SetBody(body)
			return request
		},
	)
	if berr != nil {
		return bizerr.WrapError(berr, "failed to delete cluster asts and resume tc")
	}
	if resp.StatusCode() != http.StatusOK {
		return bizerr.New(bizerr.ErrCodeRegionalAPI, "failed to delete cluster asts and resume tc, status code: %d", resp.StatusCode())
	}
	return nil
}

func (s *regionServerCliImpl) ListClusterTcs(
	ctx context.Context,
	region *entity.Region,
	clusterId string,
) (*clusteragentv1.ListTCsResp, bizerr.BizError) {
	resp, err := s.callRegion(
		ctx,
		region,
		http.MethodGet,
		operationMap["ListClusterTcs"],
		func(request *resty.Request) *resty.Request {
			request.SetPathParam(clusterIdParameter, clusterId)
			return request
		},
	)
	if err != nil {
		return nil, bizerr.WrapError(err, "failed to list cluster tcs")
	}
	if resp.StatusCode() != http.StatusOK {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "call region service failed")
	}
	var out clusteragentv1.ListTCsResp
	if err := unmarshalOptions.Unmarshal(resp.Body(), &out); err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeJsonMarshal, "failed to unmarshal response body")
	}
	return &out, nil
}
