package economics

import (
	"strings"

	"github.com/tech/sendico/pkg/merrors"
	paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
	quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
)

const (
	SettlementModeValueFixSource   = "fix_source"
	SettlementModeValueFixReceived = "fix_received"

	FeeTreatmentValueAddToSource           = "add_to_source"
	FeeTreatmentValueDeductFromDestination = "deduct_from_destination"
)

func DefaultSettlementMode() paymentv1.SettlementMode {
	return paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE
}

func DefaultFeeTreatment() quotationv2.FeeTreatment {
	return quotationv2.FeeTreatment_FEE_TREATMENT_ADD_TO_SOURCE
}

func IsValidSettlementMode(mode paymentv1.SettlementMode) bool {
	switch mode {
	case paymentv1.SettlementMode_SETTLEMENT_UNSPECIFIED,
		paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE,
		paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
		return true
	default:
		return false
	}
}

func IsValidFeeTreatment(value quotationv2.FeeTreatment) bool {
	switch value {
	case quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED,
		quotationv2.FeeTreatment_FEE_TREATMENT_ADD_TO_SOURCE,
		quotationv2.FeeTreatment_FEE_TREATMENT_DEDUCT_FROM_DESTINATION:
		return true
	default:
		return false
	}
}

func ResolveSettlementAndFee(
	mode paymentv1.SettlementMode,
	feeTreatment quotationv2.FeeTreatment,
) (paymentv1.SettlementMode, quotationv2.FeeTreatment, error) {
	if !IsValidSettlementMode(mode) {
		return paymentv1.SettlementMode_SETTLEMENT_UNSPECIFIED, quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED, merrors.InvalidArgument("settlement_mode is invalid")
	}
	if !IsValidFeeTreatment(feeTreatment) {
		return paymentv1.SettlementMode_SETTLEMENT_UNSPECIFIED, quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED, merrors.InvalidArgument("fee_treatment is invalid")
	}

	resolvedMode := mode
	if resolvedMode == paymentv1.SettlementMode_SETTLEMENT_UNSPECIFIED {
		resolvedMode = DefaultSettlementMode()
	}
	resolvedFee := feeTreatment
	if resolvedFee == quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED {
		resolvedFee = DefaultFeeTreatment()
	}
	return resolvedMode, resolvedFee, nil
}

func FeeTreatmentFromString(value string) (quotationv2.FeeTreatment, bool) {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case "", "unspecified", "fee_treatment_unspecified":
		return quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED, true
	case FeeTreatmentValueAddToSource, "fee_treatment_add_to_source":
		return quotationv2.FeeTreatment_FEE_TREATMENT_ADD_TO_SOURCE, true
	case FeeTreatmentValueDeductFromDestination, "fee_treatment_deduct_from_destination":
		return quotationv2.FeeTreatment_FEE_TREATMENT_DEDUCT_FROM_DESTINATION, true
	default:
		return quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED, false
	}
}

func ResolveFeeTreatmentFromStringOrDefault(value string) quotationv2.FeeTreatment {
	parsed, ok := FeeTreatmentFromString(value)
	if !ok || parsed == quotationv2.FeeTreatment_FEE_TREATMENT_UNSPECIFIED {
		return DefaultFeeTreatment()
	}
	return parsed
}

func FeeTreatmentValue(value quotationv2.FeeTreatment) string {
	switch value {
	case quotationv2.FeeTreatment_FEE_TREATMENT_DEDUCT_FROM_DESTINATION:
		return FeeTreatmentValueDeductFromDestination
	case quotationv2.FeeTreatment_FEE_TREATMENT_ADD_TO_SOURCE:
		return FeeTreatmentValueAddToSource
	default:
		return ""
	}
}
