package rest

import (
	"bytes"
	"io"
	"net/http"
	"net/http/httputil"
	"os"
)

// DefaultTransport is like http.DefaultTransport, but prints the contents of
// HTTP requests to os.Stderr if the DEBUG_HTTP_TRAFFIC environment variable is
// set to true.
var DefaultTransport *Transport
var defaultHttpClient *http.Client

func init() {
	DefaultTransport = &Transport{
		RoundTripper: http.DefaultTransport,
		Debug:        os.Getenv("DEBUG_HTTP_TRAFFIC") == "true",
		Output:       os.Stderr,
	}
	defaultHttpClient = &http.Client{
		Transport: DefaultTransport,
	}
}

// Transport implements HTTP round trips, but adds hooks for debugging the HTTP
// request.
type Transport struct {
	// The underlying RoundTripper.
	RoundTripper http.RoundTripper
	// Whether to write the HTTP request and response contents to Output.
	Debug bool
	// If Debug is true, write the HTTP request and response contents here. If
	// Output is nil, os.Stderr will be used.
	Output io.Writer
}

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
	if t == nil {
		panic("nil Transport")
	}
	var w io.ReadWriter = nil
	if t.Debug {
		w = new(bytes.Buffer)
		bits, err := httputil.DumpRequestOut(req, true)
		if err != nil {
			return nil, err
		}
		if len(bits) > 0 && bits[len(bits)-1] != '\n' {
			bits = append(bits, '\n')
		}
		w.Write(bits)
	}
	var res *http.Response
	var err error
	if t.RoundTripper == nil {
		res, err = http.DefaultTransport.RoundTrip(req)
	} else {
		res, err = t.RoundTripper.RoundTrip(req)
	}
	if err != nil {
		return res, err
	}
	if t.Debug {
		bits, err := httputil.DumpResponse(res, true)
		if err != nil {
			return res, err
		}
		if len(bits) > 0 && bits[len(bits)-1] != '\n' {
			bits = append(bits, '\n')
		}
		w.Write(bits)
		if t.Output == nil {
			t.Output = os.Stderr
		}
		_, err = io.Copy(t.Output, w)
		if err != nil {
			return res, err
		}
	}
	return res, err
}
