package regionalapi

import (
	"context"
	"net/url"

	ticdc_v1 "github.com/tidbcloud/cluster-service-ng/api/tidbcloud/ticdc-service/v1"
	"github.com/tidbcloud/pkgv2/bizerr"
)

const (
	createTiCDCClusterPath        = "/api/v1/ticdcClusters"
	listTiCDCClustersPath         = "/api/v1/ticdcClusters"
	getTiCDCClusterPath           = "/api/v1/ticdcClusters/{ticdc_cluster_id}"
	scaleTiCDCClusterPath         = "/api/v1/ticdcClusters/{ticdc_cluster_id}:scale"
	updateConfigTiCDCClusterPath  = "/api/v1/ticdcClusters/{ticdc_cluster_id}:updateConfig"
	updateStorageTiCDCClusterPath = "/api/v1/ticdcClusters/{ticdc_cluster_id}:updateStorage"
	deleteTiCDCClusterPath        = "/api/v1/ticdcClusters/{ticdc_cluster_id}"
	restartTiCDCClusterPath       = "/api/v1/ticdcClusters/{ticdc_cluster_id}:restart"
	getTiCDCClusterRolePath       = "/api/v1/ticdcClusterRole"
)

const (
	ticdcClusterIDPathParam  = "ticdc_cluster_id"
	ticdcClusterIDQueryParam = "ticdcClusterId"
)

type TiCDCClusterClientImpl struct {
	regionalCli RegionalClient
}

func NewTiCDCClusterClient(regionalCli RegionalClient) TiCDCClusterClient {
	return &TiCDCClusterClientImpl{
		regionalCli: regionalCli,
	}
}

func (m *TiCDCClusterClientImpl) CreateTiCDCCluster(
	ctx context.Context, region *Region, req *ticdc_v1.CreateTiCDCClusterRequest,
) (*ticdc_v1.TiCDCCluster, bizerr.BizError) {
	queryParams := make(url.Values)
	queryParams.Set(ticdcClusterIDQueryParam, req.TicdcClusterId)
	cdcCluster := new(ticdc_v1.TiCDCCluster)
	if err := m.regionalCli.Post(
		ctx, region, createTiCDCClusterPath, nil, queryParams, req.TicdcCluster, cdcCluster); err != nil {
		return nil, err
	}
	return cdcCluster, nil
}

func (m *TiCDCClusterClientImpl) ListTiCDCClusters(
	ctx context.Context, region *Region, req *ticdc_v1.ListTiCDCClustersRequest,
) (*ticdc_v1.ListTiCDCClustersResponse, bizerr.BizError) {
	queryParams, err := proto2QueryParams(req)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "build query params")
	}

	resp := new(ticdc_v1.ListTiCDCClustersResponse)
	if err := m.regionalCli.Get(ctx, region, listTiCDCClustersPath, nil, queryParams, resp); err != nil {
		return nil, err
	}
	return resp, nil
}

func (m *TiCDCClusterClientImpl) GetTiCDCCluster(
	ctx context.Context, region *Region, req *ticdc_v1.GetTiCDCClusterRequest,
) (*ticdc_v1.TiCDCCluster, bizerr.BizError) {
	pathParams := map[string]string{
		ticdcClusterIDPathParam: req.TicdcClusterId,
	}
	cdcCluster := new(ticdc_v1.TiCDCCluster)
	if err := m.regionalCli.Get(ctx, region, getTiCDCClusterPath, pathParams, nil, cdcCluster); err != nil {
		return nil, err
	}
	return cdcCluster, nil
}

func (m *TiCDCClusterClientImpl) ScaleTiCDCCluster(
	ctx context.Context, region *Region, req *ticdc_v1.ScaleTiCDCClusterRequest,
) bizerr.BizError {
	pathParams := map[string]string{
		ticdcClusterIDPathParam: req.TicdcClusterId,
	}
	return m.regionalCli.Post(ctx, region, scaleTiCDCClusterPath, pathParams, nil, req, nil)
}

func (m *TiCDCClusterClientImpl) UpdateTiCDCClusterConfig(
	ctx context.Context, region *Region, req *ticdc_v1.UpdateTiCDCClusterConfigRequest,
) bizerr.BizError {
	pathParams := map[string]string{
		ticdcClusterIDPathParam: req.TicdcClusterId,
	}
	return m.regionalCli.Post(ctx, region, updateConfigTiCDCClusterPath, pathParams, nil, req, nil)
}

func (m *TiCDCClusterClientImpl) UpdateTiCDCClusterStorage(
	ctx context.Context, region *Region, req *ticdc_v1.UpdateTiCDCClusterStorageRequest,
) bizerr.BizError {
	pathParams := map[string]string{
		ticdcClusterIDPathParam: req.TicdcClusterId,
	}
	return m.regionalCli.Post(ctx, region, updateStorageTiCDCClusterPath, pathParams, nil, req, nil)
}

func (m *TiCDCClusterClientImpl) DeleteTiCDCCluster(
	ctx context.Context, region *Region, req *ticdc_v1.DeleteTiCDCClusterRequest,
) bizerr.BizError {
	pathParams := map[string]string{
		ticdcClusterIDPathParam: req.TicdcClusterId,
	}
	return m.regionalCli.Delete(ctx, region, deleteTiCDCClusterPath, pathParams, nil)
}

func (m *TiCDCClusterClientImpl) RestartTiCDCCluster(
	ctx context.Context, region *Region, req *ticdc_v1.RestartTiCDCClusterRequest,
) bizerr.BizError {
	pathParams := map[string]string{
		ticdcClusterIDPathParam: req.TicdcClusterId,
	}
	return m.regionalCli.Post(ctx, region, restartTiCDCClusterPath, pathParams, nil, nil, nil)
}

func (m *TiCDCClusterClientImpl) GetTiCDCClusterRole(
	ctx context.Context, region *Region, req *ticdc_v1.GetTiCDCClusterRoleRequest,
) (*ticdc_v1.TiCDCClusterRole, bizerr.BizError) {
	queryParams, err := proto2QueryParams(req)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "build query params")
	}
	cdcClusterRole := new(ticdc_v1.TiCDCClusterRole)
	if err := m.regionalCli.Get(
		ctx, region, getTiCDCClusterRolePath, nil, queryParams, cdcClusterRole); err != nil {
		return nil, err
	}
	return cdcClusterRole, nil
}
