// Package http add by blacknc <blacknc@163.com> at 2023/04/03 15:46:39
package http

import (
	"context"
	"dataservices/commons/config"
	"dataservices/commons/constants"
	cdto "dataservices/internal/dto/dataapi_control"
	"fmt"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

func CreatePrivateLink(ctx context.Context, projectID, clusterID uint64, region, serviceName string) (resp *CreatePrivateLinkResp, e error) {
	url := fmt.Sprintf("/inner/dataservice/projects/%d/clusters/%d/privatelink/create", projectID, clusterID)
	req := CreatePrivateLinkReq{
		ProjectId:   projectID,
		ClusterId:   clusterID,
		ServiceName: serviceName,
	}
	resp = &CreatePrivateLinkResp{}
	e = postToDataappControl(ctx, region, url, req, resp)
	return
}

func QueryDataAppLog(ctx context.Context, region string, appId uint64, req *cdto.QueryUserExecutionLogReq) (resp *cdto.QueryUserExecutionLogRsp, e error) {
	url := fmt.Sprintf("/inner/dataservice/apps/%d/dataapp-log/query", appId)
	resp = &cdto.QueryUserExecutionLogRsp{}
	e = postToDataappControl(ctx, region, url, req, resp)
	return
}

func SubmitDataAppLogDownloadTask(ctx context.Context, region string, appId uint64, req *cdto.DownloadLogReq) (e error) {
	url := fmt.Sprintf("/inner/dataservice/apps/%d/dataapp-log/download", appId)
	resp := &cdto.BaseResp{}
	e = postToDataappControl(ctx, region, url, req, resp)
	return
}

func QueryRegionMetrics(ctx context.Context, region string, appId uint64, req *cdto.PromQueryReq) (*cdto.PromQueryRes, error) {
	url := fmt.Sprintf("/inner/dataservice/apps/%d/dataapp-metrics/query", appId)
	resp := &cdto.PromQueryRes{}
	e := postToDataappControl(ctx, region, url, req, resp)
	return resp, e
}

func DeletePrivateLink(ctx context.Context, projectID, clusterID uint64, region string, deleteCluster bool) (e error) {
	url := fmt.Sprintf("/inner/dataservice/projects/%d/clusters/%d/privatelink/delete?is_delete_cluster=%t", projectID, clusterID, deleteCluster)
	resp := &DeletePrivateLinkResp{}
	e = postToDataappControl(ctx, region, url, nil, resp)
	return
}

type CreatePrivateLinkReq struct {
	ProjectId   uint64 `json:"project_id"`
	ClusterId   uint64 `json:"cluster_id"`
	ServiceName string `json:"service_name"`
}

type CreatePrivateLinkResp struct {
	Code          int    `json:"code"`
	Message       string `json:"message"`
	VpcEndpointId string `json:"endpoint_id"`
	PrivateDNS    string `json:"private_dns"` // PrivateDNS is not "" indicate already created private link before, and no need to call `accept endpoint` API in central.
}

func (r *CreatePrivateLinkResp) GetErrCode() int {
	return r.Code
}

func (r *CreatePrivateLinkResp) GetErrMsg() string {
	return r.Message
}

type DeletePrivateLinkResp struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

func (r *DeletePrivateLinkResp) GetErrCode() int {
	return r.Code
}

func (r *DeletePrivateLinkResp) GetErrMsg() string {
	return r.Message
}

func postToDataappControl(ctx context.Context, region, url string, req interface{}, resp interface{}) (err error) {
	defer func() {
		recordHttpCounterMetric("dataservice-dataapp-control", err)
	}()
	// TODO: Dynamically obtain the provider based on the business type.
	// Currently, the system only supports AWS and Aliyun, and Aliyun will not be executed in the current module
	// so AWS is temporarily set as the default provider here.
	if !config.SupportsDataserviceControl(constants.ClusterCloudProviderAWS, region) {
		tilog.Info(ctx, "skip postToDataappControl for unsupported dataservice-control region",
			zap.String("provider", constants.ClusterCloudProviderAWS),
			zap.String("region", region),
			zap.String("url", url),
		)
		return nil
	}
	return postRequestToO11yRegion(ctx, "dataservice-dataapp-control", region, url, req, resp)
}

type CreateCustomDomainReq struct {
	Host  string `json:"host"`
	Cname string `json:"cname"`
}

type CustomDomainResp struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	State   string `json:"state"`
}

func CreateCustomDomain(ctx context.Context, appId uint64, region, host, cname string) (*CustomDomainResp, error) {
	url := fmt.Sprintf("/inner/dataservice/apps/%d/custom-domains", appId)
	req := CreateCustomDomainReq{Host: host, Cname: cname}
	var resp CustomDomainResp
	err := postToDataappControl(ctx, region, url, &req, &resp)
	return &resp, err
}

func GetCustomDomainState(ctx context.Context, appId uint64, region, host string) (*CustomDomainResp, error) {
	url := fmt.Sprintf("/inner/dataservice/apps/%d/custom-domains/%s/getState", appId, host)
	var resp CustomDomainResp
	err := postToDataappControl(ctx, region, url, map[string]string{}, &resp)
	return &resp, err
}

func DeleteCustomDomain(ctx context.Context, appId uint64, region, host string) (*CustomDomainResp, error) {
	url := fmt.Sprintf("/inner/dataservice/apps/%d/custom-domains/%s/delete", appId, host)
	var resp CustomDomainResp
	err := postToDataappControl(ctx, region, url, map[string]string{}, &resp)
	return &resp, err
}
