package httpapi_test

import (
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/coder/coder/v2/coderd/httpapi"
)

func TestDuration(t *testing.T) {
	t.Parallel()

	t.Run("MarshalJSON", func(t *testing.T) {
		t.Parallel()

		cases := []struct {
			value    time.Duration
			expected string
		}{
			{
				value:    0,
				expected: "0s",
			},
			{
				value:    1 * time.Millisecond,
				expected: "1ms",
			},
			{
				value:    1 * time.Second,
				expected: "1s",
			},
			{
				value:    1 * time.Minute,
				expected: "1m0s",
			},
			{
				value:    1 * time.Hour,
				expected: "1h0m0s",
			},
			{
				value:    1*time.Hour + 1*time.Minute + 1*time.Second + 1*time.Millisecond,
				expected: "1h1m1.001s",
			},
		}

		for _, c := range cases {
			c := c

			t.Run(c.expected, func(t *testing.T) {
				t.Parallel()

				d := httpapi.Duration(c.value)
				b, err := d.MarshalJSON()
				require.NoError(t, err)
				require.Equal(t, `"`+c.expected+`"`, string(b))
			})
		}
	})

	t.Run("UnmarshalJSON", func(t *testing.T) {
		t.Parallel()

		cases := []struct {
			value    string
			expected time.Duration
		}{
			{
				value:    "0ms",
				expected: 0,
			},
			{
				value:    "0s",
				expected: 0,
			},
			{
				value:    "1ms",
				expected: 1 * time.Millisecond,
			},
			{
				value:    "1s",
				expected: 1 * time.Second,
			},
			{
				value:    "1m",
				expected: 1 * time.Minute,
			},
			{
				value:    "1m0s",
				expected: 1 * time.Minute,
			},
			{
				value:    "1h",
				expected: 1 * time.Hour,
			},
			{
				value:    "1h0m0s",
				expected: 1 * time.Hour,
			},
			{
				value:    "1h1m1.001s",
				expected: 1*time.Hour + 1*time.Minute + 1*time.Second + 1*time.Millisecond,
			},
			{
				value:    "1h1m1s1ms",
				expected: 1*time.Hour + 1*time.Minute + 1*time.Second + 1*time.Millisecond,
			},
		}

		for _, c := range cases {
			c := c

			t.Run(c.value, func(t *testing.T) {
				t.Parallel()

				var d httpapi.Duration
				err := d.UnmarshalJSON([]byte(`"` + c.value + `"`))
				require.NoError(t, err)
				require.Equal(t, c.expected, time.Duration(d))
			})
		}
	})

	t.Run("UnmarshalJSONInt", func(t *testing.T) {
		t.Parallel()

		var d httpapi.Duration
		err := d.UnmarshalJSON([]byte("12345"))
		require.NoError(t, err)
		require.EqualValues(t, 12345, d)
	})

	t.Run("UnmarshalJSONErrors", func(t *testing.T) {
		t.Parallel()

		cases := []struct {
			value       string
			errContains string
		}{
			{
				value:       "not valid json (no double quotes)",
				errContains: "unmarshal JSON value",
			},
			{
				value:       `"not valid duration"`,
				errContains: "parse duration",
			},
			{
				value:       "{}",
				errContains: "invalid duration",
			},
		}

		for _, c := range cases {
			c := c

			t.Run(c.value, func(t *testing.T) {
				t.Parallel()

				var d httpapi.Duration
				err := d.UnmarshalJSON([]byte(c.value))
				require.Error(t, err)
				require.Contains(t, err.Error(), c.errContains)
			})
		}
	})
}
