package utils

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/pingcap/log"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

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

	return bytes.NewReader(b)
}

func Post(ctx context.Context, url string, contentType string, data string) (string, error) {

	resp, err := http.Post(url, contentType, strings.NewReader(data))
	if err != nil {
		tilog.Error(ctx, "call API  failed,", zap.String("err:", err.Error()))
		return "", err
	}
	defer resp.Body.Close() //nolint:errcheck,gosec
	result, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		tilog.Error(ctx, "get resp failed,", zap.String("err:", err.Error()))
		return "", err
	}
	response := string(result)

	tilog.Info(ctx, "API result: ", zap.Int("code：", resp.StatusCode), zap.String("response：", response))
	return response, err
}
func Get(ctx context.Context, url string, contentType string) (string, error) {

	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)

	req.Header.Set("Accept", "*/*")
	req.Header.Set("Content-Type", contentType)
	if err != nil {
		tilog.Error(ctx, "call API  failed,", zap.String("err:", err.Error()))
		return "", err
	}
	tilog.Info(ctx, "request:"+url)
	resp, err := client.Do(req)
	if err != nil {
		tilog.Error(ctx, "call API  failed:", zap.String("err:", err.Error()))
		return "", err
	}
	defer resp.Body.Close() //nolint:errcheck,gosec
	result, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		tilog.Error(ctx, "call API  failed:", zap.String("err:", err.Error()))
		return "", err
	}
	response := string(result)
	tilog.Info(ctx, "API result: ", zap.Int("code：", resp.StatusCode), zap.String("response：", response))
	return response, nil
}
func GetHeader(authorization string) map[string]string {
	header := map[string]string{
		"contentType":   "application/json",
		"authorization": authorization,
	}
	return header
}

// Post request by url
func PostWithHeader(url string, data interface{}, header *map[string]string) (string, int, error) {
	return PostBodyWithHeader(url, encodeJSON(data), header)
}
func PostBodyWithHeader(url string, body io.Reader, header *map[string]string) (string, int, error) {
	httpClient := &http.Client{Timeout: time.Second * 10}
	req, err := http.NewRequest(http.MethodPost, url, body)
	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
}

// Put request by url
func PutWithHeader(url string, data interface{}, header *map[string]string) (string, int, error) {
	httpClient := &http.Client{Timeout: time.Second * 10}
	req, err := http.NewRequest(http.MethodPut, 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
}

// Delete request by url
func DeleteWithHeader(url string, header *map[string]string) (string, int, error) {
	httpClient := &http.Client{Timeout: time.Second * 10}
	req, err := http.NewRequest(http.MethodDelete, url, nil)
	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) {
	httpClient := &http.Client{Timeout: time.Second * 10}
	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("l" + req.URL.RawQuery)
	resp, err := httpClient.Do(req)
	if nil != err {
		return "", 0, err
	}
	data, err := ioutil.ReadAll(resp.Body)
	return string(data), resp.StatusCode, err
}

// Get request by url
func GetWithHeaderTimeout(url string, params *map[string]string, header *map[string]string, timeout time.Duration) (string, int, error) {
	httpClient := &http.Client{Timeout: timeout}
	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("l" + req.URL.RawQuery)
	resp, err := httpClient.Do(req)
	if nil != err {
		return "", 0, err
	}
	data, err := ioutil.ReadAll(resp.Body)
	return string(data), resp.StatusCode, err
}
