package httputil

import (
	"bytes"
	"encoding/gob"
	"testing"
	"time"
)

type quote struct{ Author, Text string }

// With no transport installed we are not on the client, so the fetch must not
// happen and the callback must not fire — that is what leaves an SSR'd page in
// its loading state (spinner/skeleton) rather than rendering a fetch error the
// server had no way to avoid.
func TestFetchWithoutTransportDoesNotCallBack(t *testing.T) {
	defer SetClientTransport(nil)
	SetClientTransport(nil)

	called := make(chan error, 1)
	FetchGob("/api/quotes", func(_ []quote, err error) { called <- err })
	FetchJSON("/api/quotes", func(_ []quote, err error) { called <- err })

	select {
	case err := <-called:
		t.Fatalf("callback ran with no transport installed (err=%v); SSR would render an error instead of the loading state", err)
	case <-time.After(50 * time.Millisecond):
	}
}

// The client path is unchanged: with a transport installed the body is fetched
// and decoded into the same Go type the server encoded.
func TestFetchGobWithTransport(t *testing.T) {
	defer SetClientTransport(nil)
	want := []quote{{Author: "Rob Pike", Text: "When in doubt, use brute force."}}
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(want); err != nil {
		t.Fatal(err)
	}
	SetClientTransport(func(string) ([]byte, error) { return buf.Bytes(), nil })

	got := make(chan []quote, 1)
	FetchGob("/api/quotes", func(qs []quote, err error) {
		if err != nil {
			t.Errorf("FetchGob: %v", err)
		}
		got <- qs
	})

	select {
	case qs := <-got:
		if len(qs) != 1 || qs[0] != want[0] {
			t.Fatalf("decoded %v, want %v", qs, want)
		}
	case <-time.After(time.Second):
		t.Fatal("FetchGob callback never ran")
	}
}
