package persistence

import (
	"encoding/json"
	"testing"

	domainschema "github.com/nexuscrm/kernel/pkg/schema"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestBuildFieldMetadataFromColumnCarriesRollupConfigToDBMap(t *testing.T) {
	filter := "Amount__c > 0"
	resultType := models.FieldType(constants.FieldTypeCurrency)
	precision := 18
	scale := 2
	col := domainschema.ColumnDefinition{
		Name:        "Total__c",
		Label:       "Total",
		Type:        "DECIMAL(65,30)",
		LogicalType: string(constants.FieldTypeRollupSummary),
		RollupConfig: &models.RollupConfig{
			SummaryObject:     "Child__c",
			SummaryField:      "Amount__c",
			RelationshipField: "ParentId",
			CalcType:          "SUM",
			Filter:            &filter,
			ResultType:        &resultType,
			ResultPrecision:   &precision,
			ResultScale:       &scale,
		},
	}

	repo := &SchemaRepository{}
	field := repo.buildFieldMetadataFromColumn(col)
	if field.RollupConfig == nil {
		t.Fatal("buildFieldMetadataFromColumn dropped RollupConfig")
	}
	if field.RollupConfig == col.RollupConfig {
		t.Fatal("buildFieldMetadataFromColumn reused RollupConfig pointer")
	}
	if field.RollupConfig.Filter == nil || *field.RollupConfig.Filter != filter {
		t.Fatalf("field RollupConfig.Filter = %#v, want %q", field.RollupConfig.Filter, filter)
	}
	if field.RollupConfig.Filter == col.RollupConfig.Filter {
		t.Fatal("buildFieldMetadataFromColumn reused RollupConfig.Filter pointer")
	}
	if field.ReturnType == nil || *field.ReturnType != resultType || field.Precision == nil || *field.Precision != precision || field.Scale == nil || *field.Scale != scale {
		t.Fatalf("buildFieldMetadataFromColumn output metadata = %+v, want currency(18,2)", field)
	}

	values, err := repo.prepareFieldDBMap(field, "obj_parent", "fld_total")
	if err != nil {
		t.Fatalf("prepareFieldDBMap: %v", err)
	}

	got, ok := values[constants.FieldSysField_RollupConfig]
	if !ok {
		t.Fatalf("prepareFieldDBMap missing key %s", constants.FieldSysField_RollupConfig)
	}
	value, ok := got.(string)
	if !ok {
		t.Fatalf("RollupConfig DB value type = %T, want string", got)
	}

	var persisted models.RollupConfig
	if err := json.Unmarshal([]byte(value), &persisted); err != nil {
		t.Fatalf("unmarshal persisted RollupConfig: %v", err)
	}
	if persisted.CalcType != "SUM" || persisted.SummaryObject != "Child__c" || persisted.SummaryField != "Amount__c" || persisted.RelationshipField != "ParentId" {
		t.Fatalf("persisted RollupConfig = %+v, want canonical round-trip", persisted)
	}
	if persisted.Filter == nil || *persisted.Filter != filter {
		t.Fatalf("persisted Filter = %#v, want %q", persisted.Filter, filter)
	}
	if persisted.ResultType == nil || *persisted.ResultType != resultType || persisted.ResultPrecision == nil || *persisted.ResultPrecision != precision || persisted.ResultScale == nil || *persisted.ResultScale != scale {
		t.Fatalf("persisted result facets = %+v, want currency(18,2)", persisted)
	}
}

func TestHydrateRollupResultMetadataRestoresDescribeFacets(t *testing.T) {
	resultType := models.FieldType(constants.FieldTypeInt)
	precision := 18
	scale := 0
	field := &models.FieldMetadata{
		APIName: "NumberOfResponses",
		Type:    constants.FieldTypeRollupSummary,
		RollupConfig: &models.RollupConfig{
			ResultType:      &resultType,
			ResultPrecision: &precision,
			ResultScale:     &scale,
		},
	}

	hydrateRollupResultMetadata(field)
	if field.ReturnType == nil || *field.ReturnType != resultType || field.Precision == nil || *field.Precision != precision || field.Scale == nil || *field.Scale != scale {
		t.Fatalf("hydrated field = %+v, want int(18,0)", field)
	}
}
