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 (
	createTiCDCPrivateLinkPath                   = "/api/v1/ticdcSinkEndpoints"
	listTiCDCPrivateLinkPath                     = "/api/v1/ticdcSinkEndpoints"
	getTiCDCPrivateLinkPath                      = "/api/v1/ticdcSinkEndpoints/{ticdc_sink_endpoint_id}"
	deleteTiCDCPrivateLinkPath                   = "/api/v1/ticdcSinkEndpoints/{ticdc_sink_endpoint_id}"
	getPrivateLinkAuthInfoPath                   = "/api/v1/ticdcSinkEndpoints/authInfo"
	getAvailableZonesPath                        = "/api/v1/ticdcSinkEndpoints/availableZones"
	describeEndpointServiceAvailabilityZonesPath = "/api/v1/ticdcSinkEndpoints/endpointServiceAvailabilityZones"
	validateEndpointZonesPath                    = "/api/v1/ticdcSinkEndpoints/validateEndpointZones"
)

const (
	ticdcPrivateLinkIDPathParam  = "ticdc_sink_endpoint_id"
	ticdcPrivateLinkIDQueryParam = "ticdcSinkEndpointId"

	sharedPoolIDQueryParam = "sharedPoolId"
	tenantIDQueryParam     = "tenantId"
)

type TiCDCPrivateLinkClientImpl struct {
	regionalCli RegionalClient
}

func NewTiCDCPrivateLinkClient(regionalCli RegionalClient) TiCDCPrivateLinkClient {
	return &TiCDCPrivateLinkClientImpl{
		regionalCli: regionalCli,
	}
}

func (m *TiCDCPrivateLinkClientImpl) CreateTiCDCPrivateLink(
	ctx context.Context, region *Region, req *ticdc_v1.CreateTiCDCSinkEndpointRequest,
) (*ticdc_v1.TiCDCSinkEndpoint, bizerr.BizError) {
	queryParams := make(url.Values)
	queryParams.Set(ticdcPrivateLinkIDQueryParam, req.TicdcSinkEndpointId)
	privateLink := new(ticdc_v1.TiCDCSinkEndpoint)
	if err := m.regionalCli.Post(
		ctx, region, createTiCDCPrivateLinkPath,
		nil, queryParams, req.TicdcSinkEndpoint, privateLink); err != nil {
		return nil, err
	}
	return privateLink, nil
}

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

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

func (m *TiCDCPrivateLinkClientImpl) GetTiCDCPrivateLink(
	ctx context.Context, region *Region, req *ticdc_v1.GetTiCDCSinkEndpointRequest,
) (*ticdc_v1.TiCDCSinkEndpoint, bizerr.BizError) {
	pathParams := map[string]string{
		ticdcPrivateLinkIDPathParam: req.TicdcSinkEndpointId,
	}
	privateLink := new(ticdc_v1.TiCDCSinkEndpoint)
	if err := m.regionalCli.Get(
		ctx, region, getTiCDCPrivateLinkPath, pathParams, nil, privateLink); err != nil {
		return nil, err
	}
	return privateLink, nil
}

func (m *TiCDCPrivateLinkClientImpl) DeleteTiCDCPrivateLink(
	ctx context.Context, region *Region, req *ticdc_v1.DeleteTiCDCSinkEndpointRequest,
) bizerr.BizError {
	pathParams := map[string]string{
		ticdcPrivateLinkIDPathParam: req.TicdcSinkEndpointId,
	}
	queryParams := make(url.Values)
	queryParams.Set(sharedPoolIDQueryParam, req.SharedPoolId)
	return m.regionalCli.Delete(ctx, region, deleteTiCDCPrivateLinkPath, pathParams, queryParams)
}

func (m *TiCDCPrivateLinkClientImpl) GetPrivateLinkAuthInfo(ctx context.Context, region *Region,
	req *ticdc_v1.GetSinkEndpointAuthInfoRequest) (*ticdc_v1.GetSinkEndpointAuthInfoResp,
	bizerr.BizError) {
	queryParams := make(url.Values)
	queryParams.Set(sharedPoolIDQueryParam, req.SharedPoolId)
	queryParams.Set(tenantIDQueryParam, req.TenantId)
	resp := new(ticdc_v1.GetSinkEndpointAuthInfoResp)
	if err := m.regionalCli.Get(
		ctx, region, getPrivateLinkAuthInfoPath, nil, queryParams, resp); err != nil {
		return nil, err
	}
	return resp, nil
}

func (m *TiCDCPrivateLinkClientImpl) GetAvailableZones(ctx context.Context, region *Region,
	req *ticdc_v1.GetAvailableZonesRequest) (*ticdc_v1.GetAvailableZonesResponse, bizerr.BizError) {
	queryParams := make(url.Values)
	queryParams.Set(sharedPoolIDQueryParam, req.SharedPoolId)
	queryParams.Set(tenantIDQueryParam, req.TenantId)
	resp := new(ticdc_v1.GetAvailableZonesResponse)
	if err := m.regionalCli.Get(
		ctx, region, getAvailableZonesPath, nil, queryParams, resp); err != nil {
		return nil, err
	}
	return resp, nil
}

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

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

func (m *TiCDCPrivateLinkClientImpl) ValidateEndpointAvailabilityZones(
	ctx context.Context, region *Region, req *ticdc_v1.ValidateEndpointAvailabilityZonesRequest,
) bizerr.BizError {
	return m.regionalCli.Post(
		ctx, region, validateEndpointZonesPath, nil, nil, req, nil)
}
