package debug

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

// DebugRequestTransport 会打印请求和响应信息, 方便调试.
type DebugRequestTransport struct {
	RequestHeader  bool
	RequestBody    bool // RequestHeader 为 true 时,这个选项才会生效
	ResponseHeader bool
	ResponseBody   bool // ResponseHeader 为 true 时,这个选项才会生效

	// debug 信息输出到 Writer 中, 默认是 os.Stderr
	Writer io.Writer

	Transport http.RoundTripper
}

// RoundTrip implements the RoundTripper interface.
func (t *DebugRequestTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	req = cloneRequest(req) // per RoundTrip contract
	w := t.Writer
	if w == nil {
		w = os.Stderr
	}

	if t.RequestHeader {
		a, _ := httputil.DumpRequest(req, t.RequestBody)
		fmt.Fprintf(w, "%s\n\n", string(a))
	}

	resp, err := t.transport().RoundTrip(req)
	if err != nil {
		return resp, err
	}

	if t.ResponseHeader {

		b, _ := httputil.DumpResponse(resp, t.ResponseBody)
		fmt.Fprintf(w, "%s\n", string(b))
	}

	return resp, err
}

func (t *DebugRequestTransport) transport() http.RoundTripper {
	if t.Transport != nil {
		return t.Transport
	}
	return http.DefaultTransport
}

// cloneRequest returns a clone of the provided *http.Request. The clone is a
// shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header, len(r.Header))
	for k, s := range r.Header {
		r2.Header[k] = append([]string(nil), s...)
	}
	return r2
}