package sfcrmappservice

import (
	"context"
	"net/url"
	"testing"
	"time"

	querycodec "github.com/pingcap-inc/nexuscrm-app-packs/sfcrm/querycodec"
	catalogsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
)

// Database production is a fixture; parsing, calendar metadata, typed request
// validation, the production gRPC client, protobuf codecs and HTTP projection
// all execute. Exact calendar boundaries are asserted by the codec owner tests.
func TestDateQueryThroughRuntimeTransport(t *testing.T) {
	for _, tc := range []struct{ literal, field, typ string }{{"TODAY", "Due", "date"}, {"THIS_YEAR", "Due", "date"}, {"LAST_N_DAYS:30", "CreatedDate", "datetime"}} {
		t.Run(tc.literal, func(t *testing.T) {
			view := searchTestView(t, []searchObjectSpec{{APIName: "Item", Label: "Item", Fields: []searchFieldSpec{{APIName: tc.field, Label: tc.field, Type: tc.typ}}}})
			receipts := view.Receipts
			receipts.CapabilityVersion = semantic.CapabilityName
			calls := 0
			producer := &queryResponseServer{query: func(_ context.Context, req semantic.Request) (semantic.Response, error) {
				calls++
				if req.MinCatalogRevision == nil || *req.MinCatalogRevision != view.Receipts.CatalogRevision {
					t.Fatal("calendar metadata revision missing on wire")
				}
				if req.ObjectID == "User" {
					if calls != 1 || req.Filter.Kind != semantic.PredicateComparison || req.Filter.Left.Field != "Id" || req.Filter.Right.Kind != semantic.OperandTrustedContext || req.Filter.Right.TrustedContext != semantic.TrustedContextPrincipalID {
						t.Fatalf("unbound user query: %#v", req)
					}
					zone := "America/Los_Angeles"
					return semantic.Response{Done: true, TotalSize: 1, Receipts: receipts, Records: []semantic.Record{{ObjectID: "User", Fields: []semantic.Field{{Name: "TimeZoneSidKey", Value: semantic.Value{Kind: semantic.ValueString, String: &zone}}}}}}, nil
				}
				if req.ObjectID != "Item" || calls != 2 || req.Filter.Kind != semantic.PredicateAnd || len(req.Filter.Children) != 2 {
					t.Fatalf("query not lowered: %#v", req)
				}
				for _, bound := range req.Filter.Children {
					if bound.Kind != semantic.PredicateComparison || bound.Left.Field != tc.field || bound.Right.Literal == nil {
						t.Fatalf("not a typed comparison: %#v", bound)
					}
					if tc.typ == "date" {
						if bound.Right.Literal.Date == nil {
							t.Fatalf("Date lost on wire: %#v", bound)
						}
					} else {
						if bound.Right.Literal.DateTime == nil {
							t.Fatalf("DateTime lost on wire: %#v", bound)
						}
						if _, err := time.Parse(time.RFC3339Nano, *bound.Right.Literal.DateTime); err != nil {
							t.Fatal(err)
						}
					}
				}
				return semantic.Response{Done: true, Receipts: receipts}, nil
			}}
			client := queryResponseTransportProducer(t, producer)
			query := func(ctx context.Context, _ string, req semantic.Request) (semantic.Response, error) {
				return client.QueryRecords(ctx, req)
			}
			dates := &runtimeQueryDates{query: query, metadata: func(context.Context, catalogsemantic.GetRequest) (catalogsemantic.AppMetadataViewV3, error) {
				return view, nil
			}}
			h, err := NewRuntimeQueryHandler(query, func(context.Context, string, semantic.HistoryRequest) (semantic.HistoryResponse, error) {
				t.Fatal("unexpected history")
				return semantic.HistoryResponse{}, nil
			}, dates)
			if err != nil {
				t.Fatal(err)
			}
			result := h.Handle(queryDateTestContext(t), querycodec.Request{Route: querycodec.Route{Kind: querycodec.RouteQuery, Version: "v63.0"}, Query: url.Values{"q": {"SELECT Id FROM Item WHERE " + tc.field + " = " + tc.literal}}})
			if result.Status != 200 || calls != 2 {
				t.Fatalf("calls=%d response=%#v", calls, result)
			}
		})
	}
}
