package http

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

func Do(ctx context.Context, method, url string, body interface{}, headers map[string]interface{}) (result []byte, err error) {
	var (
		bodyPayload []byte
		req         *http.Request
		resp        *http.Response
	)

	if bodyPayload, err = json.Marshal(body); err != nil {
		return nil, err
	}

	if req, err = http.NewRequest(method, url, bytes.NewBuffer(bodyPayload)); err != nil {
		return nil, err
	}

	for key, val := range headers {
		req.Header.Add(key, val.(string))
	}

	client := &http.Client{}
	if resp, err = client.Do(req); err != nil {
		return nil, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()

	if result, err = ioutil.ReadAll(resp.Body); err != nil {
		return nil, err
	}

	return result, nil
}

func DoForm(ctx context.Context, method, endpoint string, body string, headers map[string]interface{}) (result []byte, err error) {
	var (
		req  *http.Request
		resp *http.Response
	)

	formValue := url.Values{}
	bodyComponent := strings.Split(body, "&")
	for _, v := range bodyComponent {
		temp := strings.Split(v, "=")
		formValue.Set(temp[0], temp[1])
	}

	if req, err = http.NewRequest(method, endpoint, strings.NewReader(formValue.Encode())); err != nil {
		return nil, err
	}

	for key, val := range headers {
		req.Header.Add(key, val.(string))
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(formValue.Encode())))

	client := &http.Client{}
	if resp, err = client.Do(req); err != nil {
		return nil, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()

	if result, err = ioutil.ReadAll(resp.Body); err != nil {
		return nil, err
	}

	return result, nil
}

func DoFormThenStream(ctx context.Context, method, endpoint string, body string, headers map[string]interface{}) (io.Reader, error) {
	var (
		req  *http.Request
		resp *http.Response
		err  error
	)

	formValue := url.Values{}
	bodyComponent := strings.Split(body, "&")
	for _, v := range bodyComponent {
		temp := strings.Split(v, "=")
		formValue.Set(temp[0], temp[1])
	}

	if req, err = http.NewRequest(method, endpoint, strings.NewReader(formValue.Encode())); err != nil {
		return nil, err
	}

	for key, val := range headers {
		req.Header.Add(key, val.(string))
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(formValue.Encode())))

	client := &http.Client{}
	if resp, err = client.Do(req); err != nil {
		return nil, err
	}
	//defer func() {
	//	_ = resp.Body.Close()
	//}()

	return resp.Body, nil
}
