package soql

import "testing"

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

	tests := []struct {
		name       string
		query      string
		wantFilter string
		wantValue  string
	}{
		{
			name:       "date literal",
			query:      "SELECT Id FROM Account WHERE CloseDate = 2026-06-01",
			wantFilter: "CloseDate == '2026-06-01'",
			wantValue:  "2026-06-01",
		},
		{
			name:       "utc datetime literal",
			query:      "SELECT Id FROM Account WHERE CreatedDate >= 2026-06-01T04:05:06Z",
			wantFilter: "CreatedDate >= '2026-06-01 04:05:06'",
			wantValue:  "2026-06-01 04:05:06",
		},
		{
			name:       "offset datetime literal",
			query:      "SELECT Id FROM Account WHERE CreatedDate < 2026-06-01T06:05:06+02:00",
			wantFilter: "CreatedDate < '2026-06-01 04:05:06'",
			wantValue:  "2026-06-01 04:05:06",
		},
		{
			name:       "fractional datetime literal",
			query:      "SELECT Id FROM Account WHERE CreatedDate > 2026-06-01T04:05:06.789Z",
			wantFilter: "CreatedDate > '2026-06-01 04:05:06'",
			wantValue:  "2026-06-01 04:05:06",
		},
	}

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

			req, err := ParseSOQL(tc.query)
			if err != nil {
				t.Fatalf("ParseSOQL() error = %v", err)
			}
			if got := predicateExpression(t, req.Filter); got != tc.wantFilter {
				t.Fatalf("predicate expression = %q, want %q", got, tc.wantFilter)
			}
			if got, ok := req.Filter.Right.Value.(string); !ok || got != tc.wantValue {
				t.Fatalf("compatibility literal = %#v (%T), want plain string %q", req.Filter.Right.Value, req.Filter.Right.Value, tc.wantValue)
			}
		})
	}
}

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

	req, err := ParseSOQL("SELECT Id FROM Account WHERE Name = '2026-06-01'")
	if err != nil {
		t.Fatalf("ParseSOQL() error = %v", err)
	}
	if got, ok := req.Filter.Right.Value.(string); !ok || got != "2026-06-01" {
		t.Fatalf("compatibility literal = %#v (%T), want ordinary string", req.Filter.Right.Value, req.Filter.Right.Value)
	}
}

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

	tests := []struct {
		name  string
		query string
	}{
		{
			name:  "invalid date literal",
			query: "SELECT Id FROM Account WHERE CloseDate = 2026-99-99",
		},
		{
			name:  "invalid datetime clock literal",
			query: "SELECT Id FROM Account WHERE CreatedDate = 2026-06-01T25:61:61Z",
		},
		{
			name:  "invalid datetime calendar literal",
			query: "SELECT Id FROM Account WHERE CreatedDate = 2026-02-29T04:05:06Z",
		},
		{
			name:  "invalid positive timezone offset hour",
			query: "SELECT Id FROM Account WHERE CreatedDate = 2026-06-01T04:05:06+24:00",
		},
		{
			name:  "invalid negative timezone offset hour",
			query: "SELECT Id FROM Account WHERE CreatedDate = 2026-06-01T04:05:06-24:00",
		},
		{
			name:  "invalid timezone offset minute",
			query: "SELECT Id FROM Account WHERE CreatedDate = 2026-06-01T04:05:06+23:60",
		},
	}

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

			if _, err := ParseSOQL(tc.query); err == nil {
				t.Fatalf("ParseSOQL(%q) error = nil, want invalid date/datetime literal error", tc.query)
			}
		})
	}
}
