package model

import "strings"

// SelectGatewayByPreference picks a gateway candidate using persisted affinity hints.
// Matching order:
// 1) gateway ID + instance ID
// 2) invoke URI
// 3) gateway ID
// 4) instance ID
// 5) first candidate fallback
func SelectGatewayByPreference(
	candidates []*GatewayInstanceDescriptor,
	gatewayID string,
	instanceID string,
	invokeURI string,
) (*GatewayInstanceDescriptor, string) {
	if len(candidates) == 0 {
		return nil, ""
	}

	gatewayID = strings.TrimSpace(gatewayID)
	instanceID = strings.TrimSpace(instanceID)
	invokeURI = strings.TrimSpace(invokeURI)

	if gatewayID != "" && instanceID != "" {
		for _, entry := range candidates {
			if entry == nil {
				continue
			}
			if strings.EqualFold(strings.TrimSpace(entry.ID), gatewayID) &&
				strings.EqualFold(strings.TrimSpace(entry.InstanceID), instanceID) {
				return entry, "exact"
			}
		}
	}

	if invokeURI != "" {
		for _, entry := range candidates {
			if entry == nil {
				continue
			}
			if strings.EqualFold(strings.TrimSpace(entry.InvokeURI), invokeURI) {
				return entry, "invoke_uri"
			}
		}
	}

	if gatewayID != "" {
		for _, entry := range candidates {
			if entry == nil {
				continue
			}
			if strings.EqualFold(strings.TrimSpace(entry.ID), gatewayID) {
				return entry, "gateway_id"
			}
		}
	}

	if instanceID != "" {
		for _, entry := range candidates {
			if entry == nil {
				continue
			}
			if strings.EqualFold(strings.TrimSpace(entry.InstanceID), instanceID) {
				return entry, "instance_id"
			}
		}
	}

	for _, entry := range candidates {
		if entry != nil {
			return entry, "rail_fallback"
		}
	}

	return nil, ""
}

// GatewayDescriptorIdentityKey returns a stable dedupe key for gateway entries.
// The key is composed from logical gateway ID + instance identity; invoke URI is
// used as a fallback identity when instance ID is missing.
func GatewayDescriptorIdentityKey(entry *GatewayInstanceDescriptor) string {
	if entry == nil {
		return ""
	}
	return GatewayIdentityKey(entry.ID, entry.InstanceID, entry.InvokeURI)
}

// GatewayIdentityKey composes a stable identity key from gateway affinity fields.
func GatewayIdentityKey(gatewayID string, instanceID string, invokeURI string) string {
	id := strings.ToLower(strings.TrimSpace(gatewayID))
	if id == "" {
		return ""
	}
	instance := strings.ToLower(strings.TrimSpace(instanceID))
	if instance == "" {
		instance = strings.ToLower(strings.TrimSpace(invokeURI))
	}
	if instance == "" {
		return id
	}
	return id + "|" + instance
}

// LessGatewayDescriptor orders gateway descriptors deterministically.
func LessGatewayDescriptor(left *GatewayInstanceDescriptor, right *GatewayInstanceDescriptor) bool {
	if left == nil {
		return right != nil
	}
	if right == nil {
		return false
	}

	if cmp := compareFolded(left.ID, right.ID); cmp != 0 {
		return cmp < 0
	}
	if cmp := compareFolded(left.InstanceID, right.InstanceID); cmp != 0 {
		return cmp < 0
	}
	if cmp := compareFolded(left.InvokeURI, right.InvokeURI); cmp != 0 {
		return cmp < 0
	}
	if cmp := compareFolded(string(left.Rail), string(right.Rail)); cmp != 0 {
		return cmp < 0
	}
	if cmp := compareFolded(left.Network, right.Network); cmp != 0 {
		return cmp < 0
	}
	return compareFolded(left.Version, right.Version) < 0
}

func compareFolded(left string, right string) int {
	l := strings.ToLower(strings.TrimSpace(left))
	r := strings.ToLower(strings.TrimSpace(right))
	switch {
	case l < r:
		return -1
	case l > r:
		return 1
	default:
		return 0
	}
}
