package orchestrator

import (
	"context"
	"time"

	"github.com/tech/sendico/pkg/api/routers/gsresponse"
	"github.com/tech/sendico/pkg/mservice"
	feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
	orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1"
)

func (s *Service) ensureRepository(ctx context.Context) error {
	if s.storage == nil {
		return errStorageUnavailable
	}
	return s.storage.Ping(ctx)
}

func (s *Service) withTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
	if d <= 0 {
		return context.WithCancel(ctx)
	}
	return context.WithTimeout(ctx, d)
}

func executeUnary[TReq any, TResp any](ctx context.Context, svc *Service, method string, handler func(context.Context, *TReq) gsresponse.Responder[TResp], req *TReq) (*TResp, error) {
	start := svc.clock.Now()
	resp, err := gsresponse.Unary(svc.logger, mservice.PaymentOrchestrator, handler)(ctx, req)
	observeRPC(method, err, svc.clock.Now().Sub(start))
	return resp, err
}

func triggerFromKind(kind orchestratorv1.PaymentKind, requiresFX bool) feesv1.Trigger {
	switch kind {
	case orchestratorv1.PaymentKind_PAYMENT_KIND_PAYOUT:
		return feesv1.Trigger_TRIGGER_PAYOUT
	case orchestratorv1.PaymentKind_PAYMENT_KIND_INTERNAL_TRANSFER:
		return feesv1.Trigger_TRIGGER_CAPTURE
	case orchestratorv1.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 *orchestratorv1.PaymentIntent) bool {
	if intent == nil {
		return false
	}
	if intent.GetKind() == orchestratorv1.PaymentKind_PAYMENT_KIND_PAYOUT {
		return true
	}
	if intent.GetDestination().GetManagedWallet() != nil || intent.GetDestination().GetExternalChain() != nil {
		return true
	}
	return false
}

func shouldRequestFX(intent *orchestratorv1.PaymentIntent) bool {
	if intent == nil {
		return false
	}
	if intent.GetRequiresFx() {
		return true
	}
	return intent.GetFx() != nil && intent.GetFx().GetPair() != nil
}
