package clients

import (
	"fmt"
	"net/http"
	"strings"

	netUrl "net/url"

	"github.com/AlchemyTelcoSolutions/xutils-go/xlogger"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func NewHTTP() *HTTPProxyClient {
	return &HTTPProxyClient{}
}

func (h *HTTPProxyClient) SetHTTPClient(client HTTPClient) *HTTPProxyClient {
	h.httpClient = client
	return h
}

func (h *HTTPProxyClient) SetLogger(l xlogger.Logger) *HTTPProxyClient {
	h.log = l
	return h
}

// DoProxy will proxy the request and adding extra headers if required
func (h *HTTPProxyClient) DoProxy(r *http.Request, urlRequest string, extraHeaders map[string]string) (*http.Response, error) {
	u, err := h.parseUrl(urlRequest)
	if err != nil {
		h.log.Error("error parsing proxy url", err)
		return nil, err
	}
	url := r.URL
	url.Scheme = u.Scheme
	url.Host = u.Host
	url.Path = u.Path
	proxyReq, err := http.NewRequest(r.Method, url.String(), r.Body)
	if err != nil {
		h.log.Error("error creating new request", err)
		return nil, err
	}

	// if User-Agent don't exist need to explicit add as a blank agent
	// in order to don't use the default "Go-http-client/1.1"
	_, ok := r.Header["User-Agent"]
	if !ok {
		r.Header.Set("User-Agent", "")
	}

	// add existing headers into the request
	logHeaders := []zapcore.Field{}
	for header, values := range r.Header {
		logHeaders = append(logHeaders, zap.String(header, strings.Join(values, ", ")))
		for _, value := range values {
			proxyReq.Header.Add(header, value)
		}
	}

	// add extra headers into the request
	for newHeader, NewValue := range extraHeaders {
		logHeaders = append(logHeaders, zap.String(newHeader, NewValue))
		proxyReq.Header.Set(newHeader, NewValue)
	}

	h.log.Info("headers", logHeaders...)

	return h.Send(proxyReq)
}

// Send do a request
func (h *HTTPProxyClient) Send(r *http.Request) (*http.Response, error) {
	return h.httpClient.Do(r)
}

func (h *HTTPProxyClient) parseUrl(url string) (*netUrl.URL, error) {
	u, err := netUrl.Parse(url)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "" || u.Host == "" || u.Path == "" {
		return nil, fmt.Errorf("no scheme, host or path in the URL")
	}
	return u, nil
}
