package persistence

import (
	"testing"

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

// TestBuildFieldMetadataFromColumn_ResolverParity proves that
// buildFieldMetadataFromColumn re-derives IsPolymorphic through
// ResolveFieldRelationshipSemantics with LifecyclePersistedRead.
//
// Legacy Type=lookup multi-target columns do not infer polymorphic ownership
// from ReferenceTo length alone; Type=reference multi-target columns continue
// to infer ownership; explicit IsPolymorphic from the column is respected.
func TestBuildFieldMetadataFromColumn_ResolverParity(t *testing.T) {
	repo := &SchemaRepository{}

	t.Run("legacy_lookup_multi_target_no_explicit_flag", func(t *testing.T) {
		// A legacy column definition with Type=lookup and multi-target
		// ReferenceTo but no explicit IsPolymorphic. Persisted-read semantics
		// must NOT infer ownership (the resolver preserves the legacy lookup
		// exception).
		col := schema.ColumnDefinition{
			Name:          "WhatId",
			Type:          "varchar(18)",
			LogicalType:   "lookup",
			Nullable:      true,
			ReferenceTo:   []string{"Account", "Contact"},
			IsPolymorphic: false,
		}
		field := repo.buildFieldMetadataFromColumn(col)
		if field.IsPolymorphic {
			t.Fatal("legacy lookup multi-target column without explicit IsPolymorphic should not be polymorphic after build")
		}
	})

	t.Run("reference_multi_target_infers_ownership", func(t *testing.T) {
		// A persisted Type=reference multi-target column should infer
		// polymorphic ownership through the resolver.
		col := schema.ColumnDefinition{
			Name:          "WhatId",
			Type:          "varchar(18)",
			LogicalType:   "reference",
			Nullable:      true,
			ReferenceTo:   []string{"Account", "Contact"},
			IsPolymorphic: false,
		}
		field := repo.buildFieldMetadataFromColumn(col)
		if !field.IsPolymorphic {
			t.Fatal("reference multi-target column should infer IsPolymorphic=true after build")
		}
	})

	t.Run("backfilled_lookup_multi_target_with_explicit_flag", func(t *testing.T) {
		// A legacy lookup multi-target column that was backfilled with
		// IsPolymorphic=true by MigrateIsPolymorphicMultiTargetBackfill.
		// The explicit flag should be respected.
		col := schema.ColumnDefinition{
			Name:          "WhoId",
			Type:          "varchar(18)",
			LogicalType:   "lookup",
			Nullable:      true,
			ReferenceTo:   []string{"Lead", "Contact"},
			IsPolymorphic: true,
		}
		field := repo.buildFieldMetadataFromColumn(col)
		if !field.IsPolymorphic {
			t.Fatal("backfilled lookup multi-target column with explicit IsPolymorphic=true should be polymorphic after build")
		}
	})

	t.Run("reference_single_target_not_polymorphic", func(t *testing.T) {
		col := schema.ColumnDefinition{
			Name:          "AccountId",
			Type:          "varchar(18)",
			LogicalType:   "reference",
			Nullable:      true,
			ReferenceTo:   []string{"Account"},
			IsPolymorphic: false,
		}
		field := repo.buildFieldMetadataFromColumn(col)
		if field.IsPolymorphic {
			t.Fatal("single-target reference without explicit flag should not be polymorphic")
		}
		if field.Type != constants.FieldTypeReference {
			t.Fatalf("type = %q, want %q", field.Type, constants.FieldTypeReference)
		}
	})

	t.Run("non_relationship_field", func(t *testing.T) {
		col := schema.ColumnDefinition{
			Name:     "Name",
			Type:     "varchar(255)",
			Nullable: false,
		}
		field := repo.buildFieldMetadataFromColumn(col)
		if field.IsPolymorphic {
			t.Fatal("non-relationship field should not be polymorphic")
		}
	})
}

func TestMapFieldToColumnDefKeepsRequiredBusinessFieldPhysicallyNullable(t *testing.T) {
	repo := &SchemaRepository{}

	col := repo.mapFieldToColumnDef(models.FieldMetadata{
		APIName:  "Resolution__c",
		Label:    "Resolution",
		Type:     constants.FieldTypeString,
		Required: true,
	})

	if !col.Nullable {
		t.Fatalf("ColumnDefinition.Nullable = false, want true; required is save-time validation, not physical NOT NULL")
	}
}

func TestMapFieldToColumnDefPreservesInteractiveIncarnation(t *testing.T) {
	repo := &SchemaRepository{}
	col := repo.mapFieldToColumnDef(models.FieldMetadata{
		ID: "fresh-field-incarnation", APIName: "Fresh__c", Type: constants.FieldTypeString,
	})
	if col.MetadataID != "fresh-field-incarnation" {
		t.Fatalf("ColumnDefinition.MetadataID = %q, want exact interactive incarnation", col.MetadataID)
	}
}

func TestMapFieldToColumnDefKeepsMasterDetailPhysicallyNotNull(t *testing.T) {
	repo := &SchemaRepository{}

	col := repo.mapFieldToColumnDef(models.FieldMetadata{
		APIName:        "ParentId",
		Label:          "Parent",
		Type:           constants.FieldTypeMasterDetail,
		Required:       true,
		IsMasterDetail: true,
		ReferenceTo:    []string{"Parent__c"},
	})

	if col.Nullable {
		t.Fatalf("master-detail ColumnDefinition.Nullable = true, want false")
	}
}
