package design

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

func Example() {
	strategy, err := Strategy("delivery")
	if err != nil {
		panic(err)
	}
	o, err := NewOrder(WithLimit(2), WithShipping(strategy))
	if err != nil {
		panic(err)
	}
	fmt.Println(o.Add(2))
	fmt.Println(o.Add(1))
	fmt.Println(o.Submit())
	fmt.Println(o.Add(1))
	_, err = NewOrder(WithLimit(0))
	fmt.Println(err)
	// Output:
	// <nil>
	// item limit exceeded
	// 520 <nil>
	// order already submitted
	// limit must be positive
}
func TestRejectedChangePreservesState(t *testing.T) {
	o, err := NewOrder(WithLimit(2))
	if err != nil {
		t.Fatal(err)
	}
	if err = o.Add(2); err != nil {
		t.Fatal(err)
	}
	if err = o.Add(1); err == nil {
		t.Fatal("wanted error")
	}
	if o.items != 2 {
		t.Fatal(o.items)
	}
}
func trace(name string, next http.Handler, events *[]string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		*events = append(*events, "enter "+name)
		defer func() { *events = append(*events, "exit "+name) }()
		next.ServeHTTP(w, r)
	})
}
func TestDecoratorOrder(t *testing.T) {
	var events []string
	core := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { events = append(events, "handler"); w.WriteHeader(204) })
	wrapped := trace("A", trace("B", core, &events), &events)
	rec := httptest.NewRecorder()
	wrapped.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
	want := "[enter A enter B handler exit B exit A]"
	if fmt.Sprint(events) != want || rec.Code != 204 {
		t.Fatal(events, rec.Code)
	}
	t.Log(events)
}

func TestOptions(t *testing.T) {
	o, err := NewOrder(WithLimit(2), WithLimit(3))
	if err != nil || o.limit != 3 {
		t.Fatalf("order=%v error=%v", o, err)
	}
	if _, err := NewOrder(nil); err == nil {
		t.Fatal("nil option accepted")
	}
	if _, err := NewOrder(WithShipping(nil)); err == nil {
		t.Fatal("nil strategy accepted")
	}
	o, err = NewOrder()
	if err != nil {
		t.Fatal(err)
	}
	if err := o.Add(1); err != nil {
		t.Fatal(err)
	}
	fee, err := o.Submit()
	if err != nil || fee != 500 {
		t.Fatal(fee, err)
	}
	t.Log("defaults: limit=10 fee=500; repeated limit uses final value=3")
}
