package analytics

import (
	"testing"

	"github.com/nexuscrm/kernel/pkg/schemautil"
	neutralcontract "github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/shared/pkg/queryspec"
)

func TestNeutralQueryResultFromModelCopiesOnlyNeutralQueryFields(t *testing.T) {
	got := neutralQueryResultFromModel(&models.QueryResult{
		TotalSize:   1,
		Done:        false,
		Records:     []models.SObject{{"Id": "001"}},
		IsAggregate: true,
	})

	if got == nil {
		t.Fatal("neutralQueryResultFromModel() = nil")
	}
	if got.TotalSize != 1 || got.Done || !got.IsAggregate || len(got.Records) != 1 {
		t.Fatalf("neutral result = %#v", got)
	}
	if _, ok := interface{}(got.Records[0]).(models.SObject); ok {
		t.Fatalf("neutral record kept models.SObject concrete type: %#v", got.Records[0])
	}
}

func TestNeutralRecordsFromSObjectsCopiesRows(t *testing.T) {
	source := []models.SObject{{"Id": "001"}}
	schemautil.SetExactDecimalForField(source[0], "Probability", schemautil.ExactDecimal("42.500000000000000001"))
	got := neutralRecordsFromSObjects(source)
	if len(got) != 1 || got[0]["Id"] != "001" {
		t.Fatalf("neutralRecordsFromSObjects() = %#v", got)
	}
	if _, ok := got[0][models.ExactDecimalMetadataKey]; ok {
		t.Fatalf("exact decimal metadata leaked into neutral record: %#v", got[0])
	}
	source[0]["Id"] = "mutated"
	if got[0]["Id"] != "001" {
		t.Fatalf("neutral record aliased source row: %#v", got)
	}
}

func TestNeutralRecordsFromSObjectsStripsNestedRelationshipMetadata(t *testing.T) {
	child := models.SObject{
		"Id":          "child-001",
		"Probability": 42.5,
	}
	models.StampObjectType(child, "Child__c")
	schemautil.SetExactDecimalForField(child, "Probability", schemautil.ExactDecimal("42.500000000000000001"))

	parent := models.SObject{
		"Id": "parent-001",
		"Children__r": map[string]interface{}{
			"totalSize": 1,
			"done":      true,
			"records":   []models.SObject{child},
		},
		"Account": map[string]interface{}{
			models.ObjectTypeMetadataKey:   "Account",
			models.ExactDecimalMetadataKey: map[string]schemautil.ExactDecimal{"Score": "1.23"},
			"Name":                         "Acme",
		},
		"Payload__c": map[string]interface{}{
			"attributes": map[string]interface{}{
				"type":   "external",
				"source": "json",
			},
		},
	}
	schemautil.SetExactDecimalForField(parent, "ParentPercent", schemautil.ExactDecimal("1.2300"))

	got := neutralRecordsFromSObjects([]models.SObject{parent})
	if len(got) != 1 {
		t.Fatalf("neutralRecordsFromSObjects() = %#v", got)
	}
	if _, ok := got[0][models.ExactDecimalMetadataKey]; ok {
		t.Fatalf("top-level exact decimal metadata leaked into neutral record: %#v", got[0])
	}
	relationship, ok := got[0]["Children__r"].(map[string]interface{})
	if !ok {
		t.Fatalf("relationship payload has type %T, want map[string]interface{}: %#v", got[0]["Children__r"], got[0]["Children__r"])
	}
	records, ok := relationship["records"].([]neutralcontract.Record)
	if !ok || len(records) != 1 {
		t.Fatalf("relationship records = %#v, want one neutral child record", relationship["records"])
	}
	if _, ok := records[0][models.ExactDecimalMetadataKey]; ok {
		t.Fatalf("nested exact decimal metadata leaked into neutral child record: %#v", records[0])
	}
	if records[0][models.ObjectTypeMetadataKey] != "Child__c" {
		t.Fatalf("nested object type = %#v, want Child__c; record=%#v", records[0][models.ObjectTypeMetadataKey], records[0])
	}
	if records[0]["Probability"] != 42.5 {
		t.Fatalf("nested public Percent value = %#v, want 42.5", records[0]["Probability"])
	}

	account, ok := got[0]["Account"].(neutralcontract.Record)
	if !ok {
		t.Fatalf("Account relationship has type %T, want neutralcontract.Record: %#v", got[0]["Account"], got[0]["Account"])
	}
	if account[models.ObjectTypeMetadataKey] != "Account" {
		t.Fatalf("Account object type = %#v, want Account; record=%#v", account[models.ObjectTypeMetadataKey], account)
	}
	if _, ok := account[models.ExactDecimalMetadataKey]; ok {
		t.Fatalf("Account exact decimal metadata leaked into neutral relationship record: %#v", account)
	}

	payload, ok := got[0]["Payload__c"].(map[string]interface{})
	if !ok {
		t.Fatalf("Payload__c has type %T, want map[string]interface{}: %#v", got[0]["Payload__c"], got[0]["Payload__c"])
	}
	attrs, ok := payload["attributes"].(map[string]interface{})
	if !ok {
		t.Fatalf("plain JSON attributes were not preserved: %#v", payload)
	}
	if attrs["type"] != "external" || attrs["source"] != "json" {
		t.Fatalf("plain JSON attributes = %#v, want external/json", attrs)
	}
}

func TestSearchWithSpecUsesPredicateLowering(t *testing.T) {
	predicate := queryspec.And(
		queryspec.FieldPredicate("OwnerId", "=", "005-user"),
		queryspec.FieldPredicate("IsActive", "=", true),
	)

	lowering, err := queryspec.LowerPredicate(predicate, queryspec.PredicateLoweringExpressionOnly)
	if err != nil {
		t.Fatalf("LowerPredicate() error = %v", err)
	}
	want := "(OwnerId = '005-user') AND (IsActive = true)"
	if lowering.Expression != want {
		t.Fatalf("LowerPredicate().Expression = %q, want %q", lowering.Expression, want)
	}
}
