package utils

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/icholy/digest"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"
	"go.uber.org/zap"
)

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 {
		log.PlainError("HttpRequest new request failed", zap.Error(err))
		return "", err
	}
	resp, err := client.Do(req)
	if err != nil {
		log.Error(ctx, "HttpRequest client.Do failed", zap.Error(err))
		return "", err
	}
	defer resp.Body.Close()
	result, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Error(ctx,"HttpRequest read body failed", zap.Error(err))
		return "", err
	}
	log.PlainInfo("http request",
		zap.String("url", reqUrl),
		zap.String("method", config.Method),
		zap.Int("status", resp.StatusCode),
		zap.String("traceId", resp.Header.Get("X-Trace-ID")))
	if resp.StatusCode != http.StatusOK {
		log.Error(ctx,"HttpRequest non-200", zap.Int("HttpCode", resp.StatusCode), zap.String("body", string(result)))
		return "", fmt.Errorf("HttpRequest failed, HttpCode=%d", resp.StatusCode)
	}

	//b, err := json.MarshalIndent(string(result), "", "\t")
	//if err != nil {
	//	panic(err)
	//}
	//
	//fmt.Println(string(b))
	log.Info(ctx,"http response body", zap.String("body", string(result)))
	return string(result), nil
}

// func GetHeader(authorization string) map[string]string {
// 	header := map[string]string{
// 		"Content-Type":      "application/json",
// 		"authorization":     authorization,
// 		"X-Test-User-Email": "letian.wang@pingcapcom",
// 		//"X-Test-User-ID":    "200058",
// 	}
// 	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 HmacAuthenticator(hmacAuthenticator *Authenticator) Option {
// 	return func(s *HttpConfig) {
// 		s.HmacAuthenticator = hmacAuthenticator
// 	}
// }

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
}

// func DoRequestByAKDev(host, url, method string, header map[string]string) {

// 	authenticator := NewClientAuthenticator(commen.Ops_ak_dev, commen.Ops_sk_dev)
// 	httpConfig := NewHttpConfig(host, url, method, header, HmacAuthenticator(authenticator))
// 	HttpRequest(*httpConfig)
// }

// func DoRequestByAKStaging(host, url, method string, header map[string]string) {

// 	authenticator := NewClientAuthenticator(commen.Ops_ak_dev, commen.Ops_sk_dev)
// 	httpConfig := NewHttpConfig(host, url, method, header, HmacAuthenticator(authenticator))
// 	HttpRequest(*httpConfig)
// }

/*
notice 发送飞书通知
func notice() {
	url := "/api/v1/message/notice"
	host := commen.Account_dev_host
	header := map[string]string{
		"contentType":   "application/json",
		"authorization": authorization,
	}

	//myConfig:=
	HttpRequest(*NewHttpConfig(host, url, http.MethodGet, header))
}
*/
