package chitin

import (
	"bytes"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"sync"
	"testing"
)

func TestNoLogger(t *testing.T) {
	var buf1 bytes.Buffer

	testLogs(t, &buf1, nil, nil)

	if buf1.Len() != 0 {
		t.Errorf("http server with no specified logger generated logs to the standard logger:\n%s", buf1.String())
	}
}

func TestHTTPLogger(t *testing.T) {
	var buf1 bytes.Buffer
	var buf2 bytes.Buffer

	testLogs(t, &buf1, log.New(&buf2, "", 0), nil)

	if buf1.Len() != 0 {
		t.Errorf("http server with (*net/http.Server).ErrorLog set generated logs to the standard logger:\n%s", buf1.String())
	}
	if buf2.Len() != 0 {
		t.Errorf("http server with (*net/http.Server).ErrorLog set generated logs to the ErrorLogger:\n%s", buf2.String())
	}
}

func TestChitinLogger(t *testing.T) {
	var buf1 bytes.Buffer
	var buf2 bytes.Buffer
	var buf3 bytes.Buffer

	testLogs(t, &buf1, log.New(&buf2, "", 0), []HandlerOpt{SetLogger(log.New(&buf3, "", 0))})

	if buf1.Len() != 0 {
		t.Errorf("http server with chitin.SetLogger generated logs to the standard logger:\n%s", buf1.String())
	}
	if buf2.Len() != 0 {
		t.Errorf("http server with chitin.SetLogger generated logs to the ErrorLog:\n%s", buf2.String())
	}

	if buf3.Len() == 0 {
		t.Errorf("http server with chitin.SetLogger did not generate logs")
	}
	if have, want := buf3.String(), "trace-id"; !strings.Contains(have, want) {
		t.Errorf("could not find %q in log output:\n%s", want, have)
	}
}

func testLogs(t *testing.T, stdlog io.Writer, errlog *log.Logger, opts []HandlerOpt) {
	log.SetOutput(stdlog)
	defer log.SetOutput(os.Stderr)

	var wg sync.WaitGroup

	srv := httptest.NewUnstartedServer(http.HandlerFunc(func(
		w http.ResponseWriter, r *http.Request) {
		wg.Add(1)
		defer wg.Done()

		w.WriteHeader(http.StatusOK)
	}))

	srv.Config.Handler = Handler(srv.Config.Handler, opts...)
	srv.Listener = wrapListener(srv.Listener)

	srv.Config.ErrorLog = errlog

	srv.Start()
	defer srv.Close()

	wg.Add(1)
	resp, err := http.Get(srv.URL)
	if err != nil {
		t.Fatalf("err = %v", err)
	}
	defer resp.Body.Close()
	wg.Done()
	wg.Wait()
}
