package utils

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"time"
)

type HConfig struct {
	Dial            time.Duration
	Timeout         time.Duration
	KeepAlive       time.Duration
	BackoffInterval time.Duration // 间隔补偿时间
	MaxConns        int           //最大连接数
	MaxIdle         int
	retryCount      int //失败重试次数
}

type HttpClient struct {
	conf       *HConfig
	client     *http.Client
	dialer     *net.Dialer
	transport  *http.Transport
	retryCount int
	//retrier    retry.Retriable
}

func (c *HConfig) NewHTTPClient() *HttpClient {
	//proxyUrl, _ := url.Parse("http://127.0.0.1:1122")
	client := &http.Client{
		Timeout: c.Timeout,
		//Transport: &http.Transport{
		//	TLSClientConfig: &tls.Config{
		//		InsecureSkipVerify: true,
		//	}, // 使用系统代理
		//	Proxy: http.ProxyURL(proxyUrl),
		//},
	}

	return &HttpClient{
		conf:   c,
		client: client,
	}
}

func (c *HttpClient) SetRetryCount(count int) {
	c.retryCount = count
}

func (c *HttpClient) Get(url string, headers map[string]string) ([]byte, error) {
	var response *http.Response

	request, err := http.NewRequest(http.MethodGet, url, nil)
	//request.URL.RawQuery = parameter

	if err != nil {
		return nil, errors.New(fmt.Sprintf("request Failed to create  err: %s", err))
	}

	if headers != nil {
		for k, v := range headers {
			request.Header.Add(k, v)
		}
	}

	response, err = c.client.Do(request)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("StatusCode ERROR : %d", response.StatusCode))
	}

	defer func() {
		if response.Body != nil {
			_ = response.Body.Close()
		}
	}()

	buf := bytes.NewBuffer(nil)
	_, err = buf.ReadFrom(response.Body)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

func (c *HttpClient) Post(url string, headers map[string]string, body interface{}) ([]byte, error) {
	return c.do(url, http.MethodPost, headers, body)
}

func (c *HttpClient) Put(url string, headers map[string]string, body interface{}) ([]byte, error) {
	return c.do(url, http.MethodPut, headers, body)
}

func (c *HttpClient) Delete(url string, headers map[string]string, body interface{}) ([]byte, error) {
	return c.do(url, http.MethodDelete, headers, body)
}

func (c *HttpClient) do(url string, method string, headers map[string]string, body interface{}) ([]byte, error) {
	var response *http.Response

	bytesData, _ := json.Marshal(body)

	bodyReader := bytes.NewReader(bytesData)
	request, err := http.NewRequest(method, url, bodyReader)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("request Failed to create  err: %s", err))
	}

	request.Header.Add("Content-Type", "application/json")

	if headers != nil {
		for k, v := range headers {
			request.Header.Add(k, v)
		}
	}

	response, err = c.client.Do(request)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("StatusCode ERROR : %d", response.StatusCode))
	}

	defer func() {
		if response.Body != nil {
			_ = response.Body.Close()
		}
	}()

	buf := bytes.NewBuffer(nil)
	_, err = buf.ReadFrom(response.Body)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}
