package model

import (
	"github.com/tech/sendico/pkg/discovery"
	"strings"
)

var supportedRailOperations = map[RailOperation]struct{}{
	discovery.RailOperationDebit:          {},
	discovery.RailOperationCredit:         {},
	discovery.RailOperationExternalDebit:  {},
	discovery.RailOperationExternalCredit: {},
	discovery.RailOperationMove:           {},
	discovery.RailOperationSend:           {},
	discovery.RailOperationFee:            {},
	discovery.RailOperationObserveConfirm: {},
	discovery.RailOperationFXConvert:      {},
	discovery.RailOperationBlock:          {},
	discovery.RailOperationRelease:        {},
}

// ParseRailOperation canonicalizes string values into a RailOperation token.
func ParseRailOperation(value string) RailOperation {
	clean := strings.ToUpper(strings.TrimSpace(value))
	if clean == "" {
		return discovery.RailOperationUnspecified
	}
	return RailOperation(clean)
}

// IsSupportedRailOperation reports whether op is recognized by payment planning.
func IsSupportedRailOperation(op RailOperation) bool {
	_, ok := supportedRailOperations[ParseRailOperation(string(op))]
	return ok
}

// NormalizeRailOperations trims, uppercases, deduplicates, and filters unknown values.
func NormalizeRailOperations(values []RailOperation) []RailOperation {
	if len(values) == 0 {
		return nil
	}
	result := make([]RailOperation, 0, len(values))
	seen := map[RailOperation]bool{}
	for _, value := range values {
		op := ParseRailOperation(string(value))
		if op == discovery.RailOperationUnspecified || !IsSupportedRailOperation(op) || seen[op] {
			continue
		}
		seen[op] = true
		result = append(result, op)
	}
	if len(result) == 0 {
		return nil
	}
	return result
}

// NormalizeRailOperationStrings normalizes string operation values.
func NormalizeRailOperationStrings(values []string) []RailOperation {
	if len(values) == 0 {
		return nil
	}
	ops := make([]RailOperation, 0, len(values))
	for _, value := range values {
		ops = append(ops, ParseRailOperation(value))
	}
	return NormalizeRailOperations(ops)
}

// HasRailOperation checks whether ops includes action.
func HasRailOperation(ops []RailOperation, action RailOperation) bool {
	want := ParseRailOperation(string(action))
	if want == discovery.RailOperationUnspecified {
		return false
	}
	for _, op := range ops {
		if ParseRailOperation(string(op)) == want {
			return true
		}
	}
	return false
}

// RailCapabilitiesFromOperations derives legacy capability flags from explicit operations.
func RailCapabilitiesFromOperations(ops []RailOperation) RailCapabilities {
	normalized := NormalizeRailOperations(ops)
	return RailCapabilities{
		CanPayIn:               HasRailOperation(normalized, discovery.RailOperationExternalDebit),
		CanPayOut:              HasRailOperation(normalized, discovery.RailOperationSend) || HasRailOperation(normalized, discovery.RailOperationExternalCredit),
		CanReadBalance:         false,
		CanSendFee:             HasRailOperation(normalized, discovery.RailOperationFee),
		RequiresObserveConfirm: HasRailOperation(normalized, discovery.RailOperationObserveConfirm),
		CanBlock:               HasRailOperation(normalized, discovery.RailOperationBlock),
		CanRelease:             HasRailOperation(normalized, discovery.RailOperationRelease),
	}
}
