package quotation

import (
	"context"
	"strings"
	"time"

	payecon "github.com/tech/sendico/pkg/payments/economics"
	feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
	fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
	quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
	sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
)

func (s *Service) withTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
	if d <= 0 {
		return context.WithCancel(ctx) //nolint:gosec // cancel func is always invoked by caller
	}
	return context.WithTimeout(ctx, d) //nolint:gosec // cancel func is always invoked by caller
}

func triggerFromKind(kind sharedv1.PaymentKind, requiresFX bool) feesv1.Trigger {
	switch kind {
	case sharedv1.PaymentKind_PAYMENT_KIND_PAYOUT:
		return feesv1.Trigger_TRIGGER_PAYOUT
	case sharedv1.PaymentKind_PAYMENT_KIND_INTERNAL_TRANSFER:
		return feesv1.Trigger_TRIGGER_CAPTURE
	case sharedv1.PaymentKind_PAYMENT_KIND_FX_CONVERSION:
		return feesv1.Trigger_TRIGGER_FX_CONVERSION
	default:
		if requiresFX {
			return feesv1.Trigger_TRIGGER_FX_CONVERSION
		}
		return feesv1.Trigger_TRIGGER_UNSPECIFIED
	}
}

func shouldEstimateNetworkFee(intent *sharedv1.PaymentIntent) bool {
	if intent == nil {
		return false
	}
	dest := intent.GetDestination()
	if dest == nil {
		return false
	}
	if dest.GetCard() != nil {
		return false
	}
	if intent.GetKind() == sharedv1.PaymentKind_PAYMENT_KIND_PAYOUT {
		return true
	}
	if dest.GetManagedWallet() != nil || dest.GetExternalChain() != nil {
		return true
	}
	return false
}

func shouldRequestFX(intent *sharedv1.PaymentIntent) bool {
	if intent == nil {
		return false
	}
	return fxIntentForQuote(intent) != nil
}

func fxIntentForQuote(intent *sharedv1.PaymentIntent) *sharedv1.FXIntent {
	if intent == nil {
		return nil
	}
	if fx := intent.GetFx(); fx != nil && fx.GetPair() != nil {
		side := fx.GetSide()
		if side == fxv1.Side_SIDE_UNSPECIFIED {
			side = fxv1.Side_SELL_BASE_BUY_QUOTE
		}
		return &sharedv1.FXIntent{
			Pair: &fxv1.CurrencyPair{
				Base:  strings.TrimSpace(fx.GetPair().GetBase()),
				Quote: strings.TrimSpace(fx.GetPair().GetQuote()),
			},
			Side:              side,
			Firm:              fx.GetFirm(),
			TtlMs:             fx.GetTtlMs(),
			PreferredProvider: strings.TrimSpace(fx.GetPreferredProvider()),
			MaxAgeMs:          fx.GetMaxAgeMs(),
		}
	}
	amount := intent.GetAmount()
	if amount == nil {
		return nil
	}
	settlementCurrency := strings.TrimSpace(intent.GetSettlementCurrency())
	if settlementCurrency == "" {
		return nil
	}
	if strings.EqualFold(amount.GetCurrency(), settlementCurrency) {
		return nil
	}
	return &sharedv1.FXIntent{
		Pair: &fxv1.CurrencyPair{
			Base:  strings.TrimSpace(amount.GetCurrency()),
			Quote: settlementCurrency,
		},
		Side: fxv1.Side_SELL_BASE_BUY_QUOTE,
	}
}

func resolvedFeeTreatmentForQuote(intent *sharedv1.PaymentIntent) quotationv2.FeeTreatment {
	if intent == nil {
		return payecon.DefaultFeeTreatment()
	}
	attrs := intent.GetAttributes()
	if len(attrs) == 0 {
		return payecon.DefaultFeeTreatment()
	}

	keys := []string{"fee_treatment", "feeTreatment"}
	for _, key := range keys {
		if value := strings.TrimSpace(attrs[key]); value != "" {
			return payecon.ResolveFeeTreatmentFromStringOrDefault(value)
		}
	}
	return payecon.DefaultFeeTreatment()
}
