package webutil

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
type Headers map[string]string

const defaultTimeout = 60 * time.Second

//BasicAuthGet adds basic auth and perform a request to path
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func BasicAuthGet(path, username, password string, headers Headers, timeout ...time.Duration) ([]byte, int, error) {
	request, err := BasicAuthRequest(path, username, password, headers)
	if err != nil {
		return nil, 0, err
	}
	return GetRequest(request, true, timeout...)
}

// BasicAuthPost adds basic auth and perform a request to path
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func BasicAuthPost(path, username, password string, payload []byte, headers Headers, timeout ...time.Duration) (resp []byte, code int, err error) {
	req, err := http.NewRequest("POST", path, bytes.NewBuffer(payload))
	if err != nil {
		return
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	req.SetBasicAuth(username, password)
	return Do(req, true, timeout...)
}

// BasicAuthPut adds basic auth and perform a request to path
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func BasicAuthPut(path, username, password string, payload []byte, headers Headers, timeout ...time.Duration) (resp []byte, code int, err error) {
	req, err := http.NewRequest("PUT", path, bytes.NewBuffer(payload))
	if err != nil {
		return
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	req.SetBasicAuth(username, password)
	return Do(req, true, timeout...)
}

//BasicAuthRequest creates a "GET" request with basic auth and return it
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func BasicAuthRequest(path, username, password string, headers Headers) (*http.Request, error) {
	request, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}
	for k, v := range headers {
		request.Header.Set(k, v)
	}
	request.SetBasicAuth(username, password)
	return request, nil
}

//Get makes a GET request to path
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func Get(path string, timeout ...time.Duration) ([]byte, int, error) {
	request, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, 0, err
	}
	return GetRequest(request, true, timeout...)
}

//GetRequest executes a request and returns an []byte response, response code, and error
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func GetRequest(request *http.Request, insecure bool, timeout ...time.Duration) ([]byte, int, error) {
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: insecure,
			},
		},
	}
	// Set a timeout if we were given one
	if len(timeout) > 0 {
		client.Timeout = timeout[1] * time.Second
	} else {
		client.Timeout = defaultTimeout
	}
	response, err := client.Do(request)
	if err != nil {
		if response != nil {
			return []byte(response.Status), 0, err
		}
		return nil, 0, err
	}
	return ResponseCheck(response)
}

//XMLBasicAuthGet adds basic auth and perform a request to path
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func XMLBasicAuthGet(path, username, password string, timeout ...time.Duration) ([]byte, int, error) {
	headers := Headers{"accept": "application/xml"}
	request, err := BasicAuthRequest(path, username, password, headers)
	if err != nil {
		return nil, 0, err
	}
	return GetRequest(request, true, timeout...)
}

//XMLBasicAuthGet adds basic auth and perform a request to path
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func XMLADXBasicAuthPost(path, method, payload, username, password string) ([]byte, int, error) {
	req, err := http.NewRequest("POST", path, bytes.NewBufferString(payload))
	if err != nil {
		return nil, -1, fmt.Errorf("error creating new http request: %v", err)
	}
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
				// VersionTLS10 required for code versions < 12.5 where TLSv1.2 is not
				//  supported on the MP
				MaxVersion: tls.VersionTLS10,
			},
		},
	}
	req.SetBasicAuth(username, password)
	req.Header.Set("Content-Type", "text/xml; charset=utf-8")
	req.Header.Set("Accept", "text/xml")
	req.Header.Set("SOAPAction", fmt.Sprintf("\"urn:webservicesapi#%v\"", method))
	resp, err := client.Do(req)
	if err != nil {
		return nil, 0, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	return ResponseCheck(resp)
}

//XMLGet performs a "GET" request to the path and appends the application/xml
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func XMLGet(path string) ([]byte, int, error) {
	request, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, 0, err
	}
	request.Header.Set("accept", "application/xml")
	return Get(path)
}

//XMLGetRequest performs a get request and sets the application/xml header to accept
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func XMLGetRequest(request *http.Request, timeout ...time.Duration) ([]byte, int, error) {
	request.Header.Set("accept", "application/xml")
	return GetRequest(request, true, timeout...)
}

//JSONAuthGet performs a request with basic auth and application/json
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func JSONAuthGet(path, username, password string, timeout ...time.Duration) ([]byte, int, error) {
	headers := Headers{"accept": "application/json"}
	request, err := BasicAuthRequest(path, username, password, headers)
	if err != nil {
		return nil, 0, err
	}
	return GetRequest(request, true, timeout...)
}

//JSONGet performs a request with the application/json header
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func JSONGet(path string, headers map[string]string, insecure bool, timeout ...time.Duration) ([]byte, int, error) {
	request, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, 0, err
	}
	for k, v := range headers {
		request.Header.Set(k, v)
	}
	request.Header.Set("accept", "application/json")
	return GetRequest(request, insecure, timeout...)
}

//JSONGetClose performs a request with application/json header and the connection close header
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func JSONGetClose(path string, headers map[string]string, insecure bool, timeout ...time.Duration) ([]byte, int, error) {
	request, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, 0, err
	}
	for k, v := range headers {
		request.Header.Set(k, v)
	}
	request.Header.Set("accept", "application/json")
	request.Header.Set("Connection", "close")
	return GetRequest(request, insecure, timeout...)
}

//JSONGetRequest performs a get request and sets the application/json header to accept
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func JSONGetRequest(request *http.Request, timeout ...time.Duration) ([]byte, int, error) {
	request.Header.Set("accept", "application/json")
	return GetRequest(request, true, timeout...)
}

//ResponseCheck reads the response and return data, status code or error it encountered.
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func ResponseCheck(response *http.Response) ([]byte, int, error) {
	defer func() {
		_ = response.Body.Close()
	}()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, response.StatusCode, err
	}
	return body, response.StatusCode, nil
}

//Post will perform a post request with the data provided.
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func Post(payload []byte, path string, headers map[string]string, insecure bool, timeout ...time.Duration) ([]byte, int, error) {
	req, err := http.NewRequest("POST", path, bytes.NewBuffer(payload))
	if err != nil {
		return nil, -1, fmt.Errorf("error creating new http request: %v", err)
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: insecure,
			},
		},
	}
	// Set timeout
	if len(timeout) > 0 {
		client.Timeout = timeout[1] * time.Second
	} else {
		client.Timeout = defaultTimeout
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, 0, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	return ResponseCheck(resp)
}

// Do will perform a request with the http request provided.
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func Do(req *http.Request, insecure bool, timeout ...time.Duration) ([]byte, int, error) {
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: insecure,
			},
		},
	}
	if len(timeout) > 0 {
		client.Timeout = timeout[1] * time.Second
	} else {
		client.Timeout = defaultTimeout
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, 0, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	return ResponseCheck(resp)
}

//JSONPost will perform a post request with the data provided, it will add content-type header json to the header map.
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func JSONPost(payload []byte, path string, headers map[string]string, insecure bool) ([]byte, int, error) {
	if headers == nil {
		headers = make(map[string]string)
	}
	headers["Content-Type"] = "application/json"
	return Post(payload, path, headers, insecure)
}

//XMLPost will perform a post request with the data provided, it will add content-type header xml to the header map.
// Deprecated: Use in new location of github.rackspace.com/gorax/webutil
func XMLPost(payload []byte, path string, headers map[string]string, insecure bool) ([]byte, int, error) {
	if headers == nil {
		headers = make(map[string]string)
	}
	headers["Content-Type"] = "application/xml"
	return Post(payload, path, headers, insecure)
}
