package plan

import (
	"context"
	"sort"
	"strings"

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

func resolveRouteNetwork(attrs map[string]string, sourceNetwork, destNetwork string) (string, error) {
	src := strings.ToUpper(strings.TrimSpace(sourceNetwork))
	dst := strings.ToUpper(strings.TrimSpace(destNetwork))
	if src != "" && dst != "" && !strings.EqualFold(src, dst) {
		return "", merrors.InvalidArgument("plan builder: source and destination networks mismatch")
	}

	override := strings.ToUpper(strings.TrimSpace(attributeLookup(attrs,
		"network",
		"route_network",
		"routeNetwork",
		"source_network",
		"sourceNetwork",
		"destination_network",
		"destinationNetwork",
	)))
	if override != "" {
		if src != "" && !strings.EqualFold(src, override) {
			return "", merrors.InvalidArgument("plan builder: source network does not match override")
		}
		if dst != "" && !strings.EqualFold(dst, override) {
			return "", merrors.InvalidArgument("plan builder: destination network does not match override")
		}
		return override, nil
	}
	if src != "" {
		return src, nil
	}
	if dst != "" {
		return dst, nil
	}
	return "", nil
}

func selectRoute(ctx context.Context, routes RouteStore, sourceRail, destRail model.Rail, network string) (*model.PaymentRoute, error) {
	if routes == nil {
		return nil, merrors.InvalidArgument("plan builder: routes store is required")
	}
	enabled := true
	result, err := routes.List(ctx, &model.PaymentRouteFilter{
		FromRail:  sourceRail,
		ToRail:    destRail,
		Network:   "",
		IsEnabled: &enabled,
	})
	if err != nil {
		return nil, err
	}
	if result == nil || len(result.Items) == 0 {
		return nil, merrors.InvalidArgument("plan builder: route not allowed")
	}
	candidates := make([]*model.PaymentRoute, 0, len(result.Items))
	for _, route := range result.Items {
		if route == nil || !route.IsEnabled {
			continue
		}
		if route.FromRail != sourceRail || route.ToRail != destRail {
			continue
		}
		if !routeMatchesNetwork(route, network) {
			continue
		}
		candidates = append(candidates, route)
	}
	if len(candidates) == 0 {
		return nil, merrors.InvalidArgument("plan builder: route not allowed")
	}
	sort.Slice(candidates, func(i, j int) bool {
		pi := routePriority(candidates[i], network)
		pj := routePriority(candidates[j], network)
		if pi != pj {
			return pi < pj
		}
		if candidates[i].Network != candidates[j].Network {
			return candidates[i].Network < candidates[j].Network
		}
		return candidates[i].ID.Hex() < candidates[j].ID.Hex()
	})
	return candidates[0], nil
}

func routeMatchesNetwork(route *model.PaymentRoute, network string) bool {
	if route == nil {
		return false
	}
	routeNetwork := strings.ToUpper(strings.TrimSpace(route.Network))
	net := strings.ToUpper(strings.TrimSpace(network))
	if routeNetwork == "" {
		return true
	}
	if net == "" {
		return false
	}
	return strings.EqualFold(routeNetwork, net)
}

func routePriority(route *model.PaymentRoute, network string) int {
	if route == nil {
		return 2
	}
	routeNetwork := strings.ToUpper(strings.TrimSpace(route.Network))
	net := strings.ToUpper(strings.TrimSpace(network))
	if net != "" && strings.EqualFold(routeNetwork, net) {
		return 0
	}
	if routeNetwork == "" {
		return 1
	}
	return 2
}
