package orchestrator

import (
	"context"
	"sort"
	"strings"

	"github.com/tech/sendico/payments/orchestrator/storage/model"
	"github.com/tech/sendico/pkg/mlogger"
)

type gatewayRegistry struct {
	logger mlogger.Logger
	static []*model.GatewayInstanceDescriptor
}

// NewGatewayRegistry aggregates static gateway descriptors.
func NewGatewayRegistry(logger mlogger.Logger, static []*model.GatewayInstanceDescriptor) GatewayRegistry {
	if len(static) == 0 {
		return nil
	}
	if logger != nil {
		logger = logger.Named("gateway_registry")
	}
	return &gatewayRegistry{
		logger: logger,
		static: cloneGatewayDescriptors(static),
	}
}

func (r *gatewayRegistry) List(ctx context.Context) ([]*model.GatewayInstanceDescriptor, error) {
	items := map[string]*model.GatewayInstanceDescriptor{}
	for _, gw := range r.static {
		if gw == nil {
			continue
		}
		id := strings.TrimSpace(gw.ID)
		if id == "" {
			continue
		}
		items[id] = cloneGatewayDescriptor(gw)
	}

	result := make([]*model.GatewayInstanceDescriptor, 0, len(items))
	for _, gw := range items {
		result = append(result, gw)
	}
	sort.Slice(result, func(i, j int) bool {
		return result[i].ID < result[j].ID
	})
	return result, nil
}

func normalizeCurrencies(values []string) []string {
	if len(values) == 0 {
		return nil
	}
	seen := map[string]bool{}
	result := make([]string, 0, len(values))
	for _, value := range values {
		clean := strings.ToUpper(strings.TrimSpace(value))
		if clean == "" || seen[clean] {
			continue
		}
		seen[clean] = true
		result = append(result, clean)
	}
	return result
}

func cloneGatewayDescriptors(src []*model.GatewayInstanceDescriptor) []*model.GatewayInstanceDescriptor {
	if len(src) == 0 {
		return nil
	}
	result := make([]*model.GatewayInstanceDescriptor, 0, len(src))
	for _, item := range src {
		if item == nil {
			continue
		}
		if cloned := cloneGatewayDescriptor(item); cloned != nil {
			result = append(result, cloned)
		}
	}
	return result
}

func cloneGatewayDescriptor(src *model.GatewayInstanceDescriptor) *model.GatewayInstanceDescriptor {
	if src == nil {
		return nil
	}
	dst := *src
	if src.Currencies != nil {
		dst.Currencies = append([]string(nil), src.Currencies...)
	}
	dst.Limits = cloneLimits(src.Limits)
	return &dst
}

func cloneLimits(src model.Limits) model.Limits {
	dst := src
	if src.VolumeLimit != nil {
		dst.VolumeLimit = map[string]string{}
		for key, value := range src.VolumeLimit {
			dst.VolumeLimit[key] = value
		}
	}
	if src.VelocityLimit != nil {
		dst.VelocityLimit = map[string]int{}
		for key, value := range src.VelocityLimit {
			dst.VelocityLimit[key] = value
		}
	}
	if src.CurrencyLimits != nil {
		dst.CurrencyLimits = map[string]model.LimitsOverride{}
		for key, value := range src.CurrencyLimits {
			dst.CurrencyLimits[key] = value
		}
	}
	return dst
}
