package cmd

import (
	"testing"
	"time"
)

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

	testCases := []struct {
		name  string
		input string
		want  int64
	}{
		{
			name:  "seconds inferred",
			input: "1712123000",
			want:  1712123000000000000,
		},
		{
			name:  "milliseconds inferred",
			input: "1712123000000",
			want:  1712123000000000000,
		},
		{
			name:  "nanoseconds inferred",
			input: "1712123000000000000",
			want:  1712123000000000000,
		},
		{
			name:  "seconds suffix",
			input: "1712123000s",
			want:  1712123000000000000,
		},
		{
			name:  "milliseconds suffix",
			input: "1712123000000ms",
			want:  1712123000000000000,
		},
		{
			name:  "nanoseconds suffix",
			input: "1712123000000000000ns",
			want:  1712123000000000000,
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			got, err := parseFlexibleTimeToUnixNano(tc.input, time.Local)
			if err != nil {
				t.Fatalf("parseFlexibleTimeToUnixNano() error = %v", err)
			}
			if got != tc.want {
				t.Fatalf("value = %d, want %d", got, tc.want)
			}
		})
	}
}

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

	t.Run("datetime uses local timezone by default", func(t *testing.T) {
		t.Parallel()

		got, err := parseFlexibleTimeToUnixNano("2026-04-03 10:04:43", time.Local)
		if err != nil {
			t.Fatalf("parseFlexibleTimeToUnixNano() error = %v", err)
		}

		want := time.Date(2026, time.April, 3, 10, 4, 43, 0, time.Local).UnixNano()
		if got != want {
			t.Fatalf("value = %d, want %d", got, want)
		}
	})

	t.Run("datetime with timezone", func(t *testing.T) {
		t.Parallel()

		got, err := parseFlexibleTimeToUnixNano("2026-04-03 02:04:43 +0000", time.Local)
		if err != nil {
			t.Fatalf("parseFlexibleTimeToUnixNano() error = %v", err)
		}

		want := time.Date(2026, time.April, 3, 2, 4, 43, 0, time.UTC).UnixNano()
		if got != want {
			t.Fatalf("value = %d, want %d", got, want)
		}
	})
}

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

	testCases := []struct {
		name      string
		input     string
		offset    time.Duration
		tolerance time.Duration
	}{
		{
			name:      "now",
			input:     "now",
			offset:    0,
			tolerance: 0,
		},
		{
			name:      "now minus minutes",
			input:     "now-30m",
			offset:    -30 * time.Minute,
			tolerance: 0,
		},
		{
			name:      "now minus compound duration",
			input:     "now-3h30m",
			offset:    -(3*time.Hour + 30*time.Minute),
			tolerance: 0,
		},
		{
			name:      "now minus days",
			input:     "now-1d",
			offset:    -24 * time.Hour,
			tolerance: 0,
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			before := time.Now()
			got, err := parseFlexibleTimeToUnixNano(tc.input, time.Local)
			after := time.Now()
			if err != nil {
				t.Fatalf("parseFlexibleTimeToUnixNano() error = %v", err)
			}

			min := before.Add(tc.offset - tc.tolerance).UnixNano()
			max := after.Add(tc.offset + tc.tolerance).UnixNano()
			if got < min || got > max {
				t.Fatalf("value = %d, want between %d and %d", got, min, max)
			}
		})
	}
}

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

	if _, err := parseFlexibleTimeToUnixNano("not-a-time", time.Local); err == nil {
		t.Fatal("parseFlexibleTimeToUnixNano() error = nil, want error")
	}

	if _, err := parseFlexibleTimeToUnixNano("now+30m", time.Local); err == nil {
		t.Fatal("parseFlexibleTimeToUnixNano() error = nil, want error for now+ expression")
	}
}
