package httpdebug

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"sort"
)

type Transport struct {
	RoundTripper http.RoundTripper

	PreFlight  func(*http.Request)
	PostFlight func(*http.Request, *http.Response, error)
}

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
	if t.PreFlight != nil {
		t.PreFlight(req)
	}
	resp, err := t.RoundTripper.RoundTrip(req)
	if t.PostFlight != nil {
		t.PostFlight(req, resp, err)
	}
	return resp, err
}

type Dialer struct {
	DialFn func(network, address string) (net.Conn, error)

	PreDial  func(network, address string)
	PostDial func(network, address string, conn net.Conn, err error)
}

func (d *Dialer) Dial(network, address string) (net.Conn, error) {
	if d.PreDial != nil {
		d.PreDial(network, address)
	}
	conn, err := d.DialFn(network, address)
	if d.PostDial != nil {
		d.PostDial(network, address, conn, err)
	}
	return conn, err
}

func CurlCommand(req *http.Request) (string, error) {
	curl := new(bytes.Buffer)
	fmt.Fprintf(curl, "curl -v -X %q", req.Method)

	// headers
	var headers []string
	for key := range req.Header {
		headers = append(headers, key)
	}
	sort.Strings(headers)
	for _, key := range headers {
		for _, value := range req.Header[key] {
			fmt.Fprintf(curl, " -H %q", fmt.Sprintf("%s: %s", key, value))
		}
	}

	// body
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return "", err
	}
	req.Body = ioutil.NopCloser(bytes.NewReader(body))
	fmt.Fprintf(curl, " -d %q", body)

	// url
	fmt.Fprintf(curl, " %q", req.URL)

	return curl.String(), nil
}
