package k8s

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"go.uber.org/zap"
)

type HTTPLinkByClusterProxy struct {
	cli                 *http.Client
	authDeco            RequestDecorator
	proxyImportEndpoint string
}

func generateImportEndpointPath(clusterID string, importID string) string {
	return fmt.Sprintf("/proxy/cluster/%s/v1alpha1/import/%s", clusterID, importID)
}

func generateImportEndpointURL(clusterProxyBaseURL string, clusterID string, importID string) string {
	proxyImportEndpointURL := &url.URL{
		Scheme: "http",
		Host:   clusterProxyBaseURL,
		Path:   generateImportEndpointPath(clusterID, importID),
	}
	return proxyImportEndpointURL.String()
}

func NewHTTPLinkByClusterProxy(clusterProxyBaseURL string, clusterID string, importID string, authDeco RequestDecorator) *HTTPLinkByClusterProxy {
	tr := &http.Transport{
		MaxConnsPerHost:     MaxConnsPerHost,
		MaxIdleConnsPerHost: MaxIdleConnsPerHost,
		IdleConnTimeout:     IdleConnTimeout,
		/* #nosec */
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	cli := &http.Client{Transport: tr}
	proxyImportEndpoint := generateImportEndpointURL(clusterProxyBaseURL, clusterID, importID)

	return &HTTPLinkByClusterProxy{
		cli:                 cli,
		authDeco:            authDeco,
		proxyImportEndpoint: proxyImportEndpoint,
	}
}

func (l *HTTPLinkByClusterProxy) Get(apiPath string) ([]byte, error) {
	taskURL, err := URLJoint(l.proxyImportEndpoint, apiPath)
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	log.Info("send GET request", zap.String("url", taskURL))
	body, statusCode, err := getHTTPResponseBody(ctx, l.cli, http.MethodGet, taskURL,
		nil,
		l.authDeco,
	)
	if err != nil {
		return nil, errors.Annotate(err, "get http response body error")
	}
	if statusCode != http.StatusOK {
		return nil, fmt.Errorf("get http response body error, status code: %d, body: %s", statusCode, string(body))
	}
	return body, nil
}

func (l *HTTPLinkByClusterProxy) Post(apiPath string, data interface{}) ([]byte, error) {
	taskURL, err := URLJoint(l.proxyImportEndpoint, apiPath)
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	log.Info("send POST request", zap.String("url", taskURL))
	body, statusCode, err := getHTTPResponseBody(ctx, l.cli, http.MethodPost, taskURL,
		strings.NewReader(fmt.Sprint(data)),
		l.authDeco,
	)
	if err != nil {
		return nil, errors.Annotate(err, "get http response body error")
	}
	if statusCode != http.StatusOK {
		return nil, fmt.Errorf("get http response body error, status code: %d, body: %s", statusCode, string(body))
	}

	return body, nil
}
