package regionalapi

import (
	"context"
	"net/url"

	ticdc_v1 "github.com/tidbcloud/infra-provider/api/tidbcloud/ticdc-service/v1"
	"github.com/tidbcloud/pkgv2/bizerr"
)

const (
	createTiCDCPrivateLinkPath = "/ticdc-service/api/v1/ticdcSinkEndpoints"
	listTiCDCPrivateLinkPath   = "/ticdc-service/api/v1/ticdcSinkEndpoints"
	getTiCDCPrivateLinkPath    = "/ticdc-service/api/v1/ticdcSinkEndpoints/{ticdc_sink_endpoint_id}"
	deleteTiCDCPrivateLinkPath = "/ticdc-service/api/v1/ticdcSinkEndpoints/{ticdc_sink_endpoint_id}"
	getPrivateLinkAuthInfoPath = "/ticdc-service/api/v1/ticdcSinkEndpoints/authInfo"
	getAvailableZonesPath      = "/ticdc-service/api/v1/ticdcSinkEndpoints/availableZones"
	validateEndpointZonesPath  = "/ticdc-service/api/v1/ticdcSinkEndpoints/validateEndpointZones"
)

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

	tidbClusterIDQueryParam = "tidbClusterId"
	tenantIDQueryParam      = "tenantId"
	projectIDQueryParam     = "projectId"
)

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,
	}
	return m.regionalCli.Delete(ctx, region, deleteTiCDCPrivateLinkPath, pathParams, nil)
}

func (m *TiCDCPrivateLinkClientImpl) GetPrivateLinkAuthInfo(ctx context.Context, region *Region,
	req *ticdc_v1.GetSinkEndpointAuthInfoRequest) (*ticdc_v1.GetSinkEndpointAuthInfoResp,
	bizerr.BizError) {
	queryParams := make(url.Values)
	queryParams.Set(tenantIDQueryParam, req.TenantId)
	queryParams.Set(ticdcPrivateLinkIDQueryParam, req.TicdcSinkEndpointId)
	if req.TidbClusterId != "" {
		queryParams.Set(tidbClusterIDQueryParam, req.TidbClusterId)
	}
	if req.ProjectId != "" {
		queryParams.Set(projectIDQueryParam, req.ProjectId)
	}
	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(tenantIDQueryParam, req.TenantId)
	if req.TidbClusterId != "" {
		queryParams.Set(tidbClusterIDQueryParam, req.TidbClusterId)
	}
	if req.ProjectId != "" {
		queryParams.Set(projectIDQueryParam, req.ProjectId)
	}
	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) ValidateEndpointAvailabilityZones(
	ctx context.Context, region *Region, req *ticdc_v1.ValidateEndpointAvailabilityZonesRequest,
) bizerr.BizError {
	return m.regionalCli.Post(
		ctx, region, validateEndpointZonesPath, nil, nil, req, nil)
}
