package httpclient

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"time"

	"io/ioutil"
	"net/http"

	"github.com/pingcap/log"
)

var (
	// 3 seconds timeout
	httpClient = &http.Client{Timeout: time.Second * 20}
)

// Get request by url
func Get(url string) (string, int, error) {
	return GetWithHeader(url, nil, nil)
}

func encodeJSON(data interface{}) io.Reader {
	b, _ := json.Marshal(data)

	return bytes.NewReader(b)
}

// Get request by url
func PostWithHeader(url string, data interface{}, header *map[string]string) (string, int, error) {
	req, err := http.NewRequest(http.MethodPost, url, encodeJSON(data))
	if err != nil {
		return "", 0, err
	}
	if header != nil {
		for k, v := range *header {
			req.Header.Set(k, v)
		}
	}
	resp, err := httpClient.Do(req)
	if nil != err {
		return "", 0, err
	}
	respdata, err := ioutil.ReadAll(resp.Body)
	return string(respdata), resp.StatusCode, err
}

// Get request by url
func GetWithHeader(url string, params *map[string]string, header *map[string]string) (string, int, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return "", 0, err
	}
	if header != nil {
		for k, v := range *header {
			req.Header.Set(k, v)
		}
	}
	if params != nil {
		q := req.URL.Query()
		for k, v := range *params {
			q.Add(k, v)
		}
		req.URL.RawQuery = q.Encode()
	}
	log.Info(fmt.Sprintf("URL is %s , Header is %v", req.URL, req.Header))
	resp, err := httpClient.Do(req)
	if nil != err {
		return "", 0, err
	}
	data, err := ioutil.ReadAll(resp.Body)
	return string(data), resp.StatusCode, err
}

func RequestWithHeader(ctx context.Context, method string, url string, queryString *map[string]string, header *map[string]string, payload interface{}) (string, int, error) {
	var body io.Reader
	if payload != nil {
		body = encodeJSON(payload)
	}

	req, err := http.NewRequestWithContext(ctx, method, url, body)
	if err != nil {
		return "", 0, err
	}
	if header != nil {
		for k, v := range *header {
			req.Header.Set(k, v)
		}
	}
	if method != http.MethodGet {
		req.Header.Set("Content-Type", "application/json")
	}

	if queryString != nil {
		q := req.URL.Query()
		for k, v := range *queryString {
			q.Add(k, v)
		}
		req.URL.RawQuery = q.Encode()
	}
	resp, err := httpClient.Do(req)
	if nil != err {
		return "", 0, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	return string(data), resp.StatusCode, err
}
