package config

import (
	"encoding/json"
	"testing"
	"time"
)

func TestDurationMarshal(t *testing.T) {
	cases := map[string]struct {
		in     string
		want   Duration
		wantJS string
	}{
		"empty string": {
			wantJS: `"0s..0s"`,
		},
		"random in": {
			in:     "abc",
			want:   Duration{},
			wantJS: `"0s..0s"`,
		},
		"1 dur": {
			in: "1m",
			want: Duration{
				least: time.Minute,
				most:  time.Minute,
			},
			wantJS: `"1m0s..1m0s"`,
		},
		"descending": {
			in: "2m..1m",
			want: Duration{
				least: time.Minute,
				most:  2 * time.Minute,
			},
			wantJS: `"1m0s..2m0s"`,
		},
		"happy span": {
			in: "1m..2m",
			want: Duration{
				least: time.Minute,
				most:  2 * time.Minute,
			},
			wantJS: `"1m0s..2m0s"`,
		},
		"multi unit descending": {
			in: "1h1m..2m3ms",
			want: Duration{
				least: 2*time.Minute + 3*time.Millisecond,
				most:  time.Hour + time.Minute,
			},
			wantJS: `"2m0.003s..1h1m0s"`,
		},
	}

	for name, d := range cases {
		c := d
		t.Run(name, func(t *testing.T) {
			var got Duration
			err := json.Unmarshal([]byte(`"`+c.in+`"`), &got)
			if got != c.want {
				t.Fatalf("err %v: want %+v, got %+v", err, c.want, got)
			}
			js, _ := json.Marshal(got)
			if string(js) != c.wantJS {
				t.Fatalf("want marshalled %s, got %s", c.wantJS, js)
			}
			var got2 Duration
			json.Unmarshal(js, &got2)
			if got != got2 {
				t.Fatalf("want unmarshal-marshal-unmarshal %+v, got %+v", got, got2)
			}
		})
	}
}

func TestDurationGet(t *testing.T) {
	t.Run("same", func(t *testing.T) {
		d := Duration{least: time.Second, most: time.Second}
		for i := 0; i < 50; i++ {
			if got := d.Get(); got != time.Second {
				t.Error(got)
			}
		}
	})

	t.Run("1ms span", func(t *testing.T) {
		d := Duration{least: time.Second, most: time.Second + time.Millisecond}
		for i := 0; i < 50; i++ {
			if got := d.Get(); got != time.Second {
				t.Error(got)
			}
		}
	})

	t.Run("5s span", func(t *testing.T) {
		d := Duration{least: time.Second, most: 6 * time.Second}
		for i := 0; i < 50; i++ {
			if got := d.Get(); got > time.Second*6 || got < time.Second {
				t.Error(got)
			}
		}
	})
}
