package utils

import (
	"context"
	"fmt"
	"github.com/icholy/digest"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"io"
	"net/http"
	"strings"
)

func HttpRequest(ctx context.Context, config HttpConfig) (string, error) {
	reqUrl := config.Host + config.Url
	//reqUrl = url.QueryEscape(reqUrl)
	var req *http.Request
	var err error
	client := &http.Client{}
	// digest request
	if config.Transport != nil {
		client.Transport = config.Transport
	}
	var body *strings.Reader
	// post ,put, Delete request
	if len(config.BodyJson) > 0 {
		body = strings.NewReader(config.BodyJson)
		req, err = http.NewRequest(config.Method, reqUrl, body)
	} else {
		// get request
		req, err = http.NewRequest(config.Method, reqUrl, nil)
	}
	req.Header.Set("Accept", "*/*")

	for k, v := range config.Header {
		req.Header.Set(k, v)
	}
	if err != nil {
		tilog.Error(ctx, "Http request error", zap.Error(err))

		return "", err
	}

	resp, err := client.Do(req)
	if err != nil {
		tilog.Error(ctx, "Http resp error", zap.Error(err))
		return "", err
	}
	defer resp.Body.Close()
	result, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	//fmt.Println("")
	//fmt.Sprintln("url:", reqUrl, " ", config.Method)
	tilog.Info(ctx, "Http request "+fmt.Sprintf("url: %s,   %s,  body:  %s", reqUrl, config.Method, config.BodyJson))
	//fmt.Println("X-Debug-Trace-Id:", resp.Header.Get("X-Debug-Trace-Id"))
	//fmt.Println("Date:", resp.Header.Get("Date"))

	tilog.Info(ctx, "bodyJson param: "+fmt.Sprintf(" %s", config.BodyJson))
	tilog.Info(ctx, "HttpCode= "+fmt.Sprintf(" %d", resp.StatusCode))
	tilog.Info(ctx, "Http response: "+fmt.Sprintf(" %s", string(result)))
	//fmt.Println(string(result))
	return string(result), nil
}

func GetHeader(authorization string) map[string]string {
	header := map[string]string{
		"Content-Type":  "application/json",
		"authorization": authorization,
	}
	return header
}

type HttpConfig struct {
	Host      string
	Url       string
	Method    string
	Header    map[string]string
	BodyJson  string
	Transport *digest.Transport
}
type Option func(*HttpConfig)

func BodyJson(bodyJson string) Option {
	return func(s *HttpConfig) {
		s.BodyJson = bodyJson
	}
}

func Transport(transport *digest.Transport) Option {
	return func(s *HttpConfig) {
		s.Transport = transport
	}
}

func NewHttpConfig(host string, url string, method string, header map[string]string, options ...Option) *HttpConfig {
	srv := HttpConfig{
		Host:   host,
		Url:    url,
		Method: method,
		Header: header,
	}
	for _, option := range options {
		option(&srv)
	}
	//...
	return &srv
}
