package xarth

import (
	"net/http"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"code.justin.tv/rhys/nursery/xarth/internal/trace"
	"github.com/kr/logfmt"
)

func TestTraceSpanHeader(t *testing.T) {
	// generate a random trace id
	ctx := trace.ContextFromHeader(context.Background(), nil)

	// force the span id to be non-empty
	ctx0 := ctx
	for i := 0; i < 22+1; i++ {
		ctx = trace.NewSpan(ctx0)
	}
	ctx1 := ctx
	for i := 0; i < 33+1; i++ {
		ctx = trace.NewSpan(ctx1)
	}
	h := make(http.Header)
	trace.AugmentHeader(ctx, h)
	ctx = trace.ContextFromHeader(context.Background(), h)
	if have, want := trace.Logfmt(ctx), `".22.33"`; !strings.Contains(have, want) {
		t.Errorf("tx.SubID; %q does not contain %q", have, want)
		return
	}

	// our test requires a custom http client, arrange for it to be installed
	// for this test
	defer func(client *http.Client) {
		http.DefaultClient = client
	}(http.DefaultClient)
	http.DefaultClient = Client(ctx)

	type traceVals struct {
		TraceID   string `logfmt:"trace-id"`
		TraceSpan string `logfmt:"trace-span"`
	}

	var parent traceVals
	err := logfmt.Unmarshal([]byte(trace.Logfmt(ctx)), &parent)
	if err != nil {
		t.Errorf("logfmt unmarshal %v", err)
		return
	}

	children := make(chan traceVals, 5)

	for i := 0; i < cap(children); i++ {
		resp, err := testGet(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ctx, ok := Context(w, r)
			if !ok {
				t.Errorf("couldn't get context")
				return
			}

			var child traceVals
			err := logfmt.Unmarshal([]byte(trace.Logfmt(ctx)), &child)
			if err != nil {
				t.Errorf("logfmt unmarshal %v", err)
				return
			}

			children <- child

			if have, want := child.TraceID, parent.TraceID; have != want {
				t.Errorf("transaction id was not successfully transmitted: %q != %q", have, want)
			}
			// if have, want := subTx.SubID, tx.SubID+suffix; have != want {
			// 	t.Errorf("transaction subspan was not successfully transmitted: %q != %q", have, want)
			// }
		}), "/")
		if err != nil {
			t.Errorf("http request failed: %v", err)
			return
		}
		resp.Body.Close()
	}
	close(children)

	spans := make(map[string]struct{}, cap(children))
	for child := range children {
		if _, ok := spans[child.TraceSpan]; ok {
			t.Errorf("duplicate span: %q", child.TraceSpan)
		}
		spans[child.TraceSpan] = struct{}{}
	}
}
