package client

import (
	"context"
	"encoding/json"
	"errors"
	logger "eta/eta_mini_ht_api/common/component/log"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"time"
)

type HttpClient struct {
	*http.Client
	maxRetries     int
	retryDelayFunc RetryDelayFunc
}

// NewClient 构造函数,其中 delayFunc 参数是可选的
func NewClient(timeout time.Duration, maxRetries int, delayFunc ...RetryDelayFunc) *HttpClient {
	var df RetryDelayFunc
	if len(delayFunc) > 0 {
		df = delayFunc[0]
	} else {
		df = defaultRetryDelayFunc
	}
	return &HttpClient{
		Client:         &http.Client{Timeout: timeout},
		maxRetries:     maxRetries,
		retryDelayFunc: df,
	}
}

func DefaultClient() *HttpClient {
	return NewClient(time.Second*10, 3)
}
func defaultRetryDelayFunc(attempt int) time.Duration {
	delay := time.Duration(attempt) * time.Second
	if attempt > 0 {
		delay *= 2
	}
	return delay
}

type RetryDelayFunc func(attempt int) time.Duration

func retryErr(err error) bool {
	return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled)
}

// DoWithRetry 发送带有重试机制的HTTP请求,允许用户自定义重试延迟逻辑
func (hc *HttpClient) DoWithRetry(ctx context.Context, req *http.Request) (resp *http.Response, err error) {
	attempt := 0
	for {
		resp, err = hc.Do(req.WithContext(ctx))
		if err != nil && retryErr(err) {
			if attempt >= hc.maxRetries {

				return nil, fmt.Errorf("请求失败: %w", err)
			}
			attempt++
			delay := hc.retryDelayFunc(attempt)
			time.Sleep(delay)
			continue
		}
		return
	}
}

func (hc *HttpClient) Post(url string, data interface{}) (resp *http.Response, err error) {
	dataStr, err := json.Marshal(data)
	if err != nil {
		logger.Error("请求data json序列化失败,err:" + err.Error())
	}
	body := io.NopCloser(strings.NewReader(string(dataStr)))
	req, err := http.NewRequest(http.MethodPost, url, body)
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		logger.Error("创建POST请求失败: %v", err)
	}
	resp, err = hc.DoWithRetry(req.Context(), req)
	code := resp.StatusCode
	if code != 200 {
		logger.Error("请求错误应答,状态码:%d", code)
		errMsg := fmt.Sprintf("请求状态码异常,StatusCode:[%d]", code)
		respBody, respErr := io.ReadAll(resp.Body)
		if respErr != nil {
			logger.Error("读取body失败,err:%v", err)
			err = errors.New(errMsg)
			return
		}
		logger.Error("请求错误应答,body:%s", string(respBody))
		errMsg = fmt.Sprintf("%s,body:%s", errMsg, string(respBody))
		err = errors.New(errMsg)
		return
	}
	return
}

func (hc *HttpClient) Get(url string) (resp *http.Response, err error) {
	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
	if err != nil {
		log.Fatalf("创建请求失败: %v", err)
	}
	resp, err = hc.DoWithRetry(req.Context(), req)
	return
}