package schema

import (
	"strings"

	"github.com/nexuscrm/shared/pkg/constants"
)

// IsPolymorphicReferenceColumn reports whether a table-definition column owns a
// server-managed polymorphic discriminator. This is intentionally shape-based:
// a transitional single-target reference may set IsPolymorphic=true so the
// discriminator exists before public multi-target CRUD is enabled.
func IsPolymorphicReferenceColumn(col ColumnDefinition) bool {
	if len(col.ReferenceTo) == 0 {
		return false
	}
	if col.IsPolymorphic {
		return true
	}
	return len(col.ReferenceTo) > 1 &&
		strings.EqualFold(col.LogicalType, string(constants.FieldTypeReference))
}

// PolymorphicDiscriminatorColumnName returns the storage column for the lookup
// target object's API name.
func PolymorphicDiscriminatorColumnName(fieldAPIName string) string {
	return fieldAPIName + constants.PolymorphicTypeSuffix
}

// PolymorphicDiscriminatorColumn returns the generated discriminator column for
// a polymorphic reference column.
func PolymorphicDiscriminatorColumn(col ColumnDefinition) ColumnDefinition {
	return ColumnDefinition{
		Name:                             PolymorphicDiscriminatorColumnName(col.Name),
		Label:                            strings.TrimSpace(col.Label + " Type"),
		Type:                             "VARCHAR(255)",
		LogicalType:                      string(constants.FieldTypeString),
		Nullable:                         true,
		GeneratedForPolymorphicReference: col.Name,
	}
}

// IsPolymorphicDiscriminatorColumn reports whether a column was generated from
// companion polymorphic reference metadata. A raw "_type" suffix alone is not
// enough: ordinary fields such as Notification.notification_type remain normal
// metadata fields.
func IsPolymorphicDiscriminatorColumn(col ColumnDefinition) bool {
	return strings.TrimSpace(col.GeneratedForPolymorphicReference) != ""
}

// ExpandPolymorphicDiscriminatorColumns appends missing discriminator columns
// immediately after their owning reference fields. Existing explicit columns
// are preserved, which keeps the helper idempotent for mixed legacy specs.
func ExpandPolymorphicDiscriminatorColumns(def TableDefinition) TableDefinition {
	if len(def.Columns) == 0 {
		return def
	}

	existing := make(map[string]bool, len(def.Columns))
	generatedBy := make(map[string]string)
	for _, col := range def.Columns {
		existing[strings.ToLower(col.Name)] = true
		if IsPolymorphicReferenceColumn(col) {
			generatedBy[strings.ToLower(PolymorphicDiscriminatorColumnName(col.Name))] = col.Name
		}
	}

	expanded := make([]ColumnDefinition, 0, len(def.Columns))
	for _, col := range def.Columns {
		if parentName := generatedBy[strings.ToLower(col.Name)]; parentName != "" && !IsPolymorphicReferenceColumn(col) {
			col.GeneratedForPolymorphicReference = parentName
		}
		expanded = append(expanded, col)
		if !IsPolymorphicReferenceColumn(col) {
			continue
		}
		typeCol := PolymorphicDiscriminatorColumn(col)
		typeKey := strings.ToLower(typeCol.Name)
		if existing[typeKey] {
			continue
		}
		expanded = append(expanded, typeCol)
		existing[typeKey] = true
	}
	def.Columns = expanded
	return def
}

// ExpandPolymorphicDiscriminatorColumnsForDefinitions applies discriminator
// expansion to a slice of table definitions without mutating the input slice.
func ExpandPolymorphicDiscriminatorColumnsForDefinitions(defs []TableDefinition) []TableDefinition {
	out := make([]TableDefinition, len(defs))
	for i, def := range defs {
		out[i] = ExpandPolymorphicDiscriminatorColumns(def)
	}
	return out
}
