package orchestrator

import (
	"strings"

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

func railFromEndpoint(endpoint model.PaymentEndpoint, attrs map[string]string, isSource bool) (model.Rail, string, error) {
	override := railOverrideFromAttributes(attrs, isSource)
	if override != model.RailUnspecified {
		return override, networkFromEndpoint(endpoint), nil
	}
	switch endpoint.Type {
	case model.EndpointTypeLedger:
		return model.RailLedger, "", nil
	case model.EndpointTypeManagedWallet, model.EndpointTypeExternalChain:
		return model.RailCrypto, networkFromEndpoint(endpoint), nil
	case model.EndpointTypeCard:
		return model.RailCardPayout, "", nil
	default:
		return model.RailUnspecified, "", merrors.InvalidArgument("plan builder: unsupported payment endpoint")
	}
}

func railOverrideFromAttributes(attrs map[string]string, isSource bool) model.Rail {
	if len(attrs) == 0 {
		return model.RailUnspecified
	}
	keys := []string{"source_rail", "sourceRail"}
	if !isSource {
		keys = []string{"destination_rail", "destinationRail"}
	}
	lookup := map[string]struct{}{}
	for _, key := range keys {
		lookup[strings.ToLower(key)] = struct{}{}
	}
	for key, value := range attrs {
		if _, ok := lookup[strings.ToLower(strings.TrimSpace(key))]; !ok {
			continue
		}
		rail := parseRailValue(value)
		if rail != model.RailUnspecified {
			return rail
		}
	}
	return model.RailUnspecified
}

func parseRailValue(value string) model.Rail {
	val := strings.ToUpper(strings.TrimSpace(value))
	switch val {
	case string(model.RailCrypto):
		return model.RailCrypto
	case string(model.RailProviderSettlement):
		return model.RailProviderSettlement
	case string(model.RailLedger):
		return model.RailLedger
	case string(model.RailCardPayout):
		return model.RailCardPayout
	case string(model.RailFiatOnRamp):
		return model.RailFiatOnRamp
	default:
		return model.RailUnspecified
	}
}

func gatewayNetworkForRail(rail model.Rail, sourceRail, destRail model.Rail, sourceNetwork, destNetwork string) string {
	switch rail {
	case model.RailCrypto:
		if sourceRail == model.RailCrypto {
			return strings.ToUpper(strings.TrimSpace(sourceNetwork))
		}
		if destRail == model.RailCrypto {
			return strings.ToUpper(strings.TrimSpace(destNetwork))
		}
	case model.RailFiatOnRamp:
		if sourceRail == model.RailFiatOnRamp {
			return strings.ToUpper(strings.TrimSpace(sourceNetwork))
		}
		if destRail == model.RailFiatOnRamp {
			return strings.ToUpper(strings.TrimSpace(destNetwork))
		}
	}
	return ""
}

func networkFromEndpoint(endpoint model.PaymentEndpoint) string {
	switch endpoint.Type {
	case model.EndpointTypeManagedWallet:
		if endpoint.ManagedWallet != nil && endpoint.ManagedWallet.Asset != nil {
			return strings.ToUpper(strings.TrimSpace(endpoint.ManagedWallet.Asset.GetChain()))
		}
	case model.EndpointTypeExternalChain:
		if endpoint.ExternalChain != nil && endpoint.ExternalChain.Asset != nil {
			return strings.ToUpper(strings.TrimSpace(endpoint.ExternalChain.Asset.GetChain()))
		}
	}
	return ""
}
