package orchestrator

import (
	"strings"

	"github.com/tech/sendico/payments/orchestrator/storage/model"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/model/account_role"
	"github.com/tech/sendico/pkg/payments/rail"
	paymenttypes "github.com/tech/sendico/pkg/payments/types"
	orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1"
)

const (
	providerSettlementMetaPaymentIntentID = "payment_ref"
	providerSettlementMetaQuoteRef        = "quote_ref"
	providerSettlementMetaTargetChatID    = "target_chat_id"
	providerSettlementMetaOutgoingLeg     = "outgoing_leg"
	providerSettlementMetaSourceAmount    = "source_amount"
	providerSettlementMetaSourceCurrency  = "source_currency"
)

func (p *paymentExecutor) buildProviderSettlementTransferRequest(payment *model.Payment, step *model.PaymentStep, operationRef string, amount *paymenttypes.Money, quote *orchestratorv1.PaymentQuote, idx int, fromRole, toRole *account_role.AccountRole) (rail.TransferRequest, error) {
	if payment == nil || step == nil {
		return rail.TransferRequest{}, merrors.InvalidArgument("provider settlement: payment and step are required")
	}
	if amount == nil {
		return rail.TransferRequest{}, merrors.InvalidArgument("provider settlement: amount is required")
	}
	requestID := planStepIdempotencyKey(payment, idx, step)
	if requestID == "" {
		return rail.TransferRequest{}, merrors.InvalidArgument("provider settlement: idempotency key is required")
	}
	intentRef := strings.TrimSpace(payment.Intent.Ref)
	if intentRef == "" {
		return rail.TransferRequest{}, merrors.InvalidArgument("provider settlement: intention ref is required")
	}
	paymentRef := strings.TrimSpace(payment.PaymentRef)
	if paymentRef == "" {
		return rail.TransferRequest{}, merrors.InvalidArgument("provider settlement: payment_ref is required")
	}
	metadata := cloneMetadata(payment.Metadata)
	if metadata == nil {
		metadata = map[string]string{}
	}
	metadata[providerSettlementMetaPaymentIntentID] = paymentRef
	if quoteRef := paymentGatewayQuoteRef(payment, quote); quoteRef != "" {
		metadata[providerSettlementMetaQuoteRef] = quoteRef
	}
	if chatID := paymentGatewayTargetChatID(payment); chatID != "" {
		metadata[providerSettlementMetaTargetChatID] = chatID
	}
	if strings.TrimSpace(metadata[providerSettlementMetaOutgoingLeg]) == "" {
		metadata[providerSettlementMetaOutgoingLeg] = strings.ToLower(strings.TrimSpace(string(step.Rail)))
	}
	if strings.TrimSpace(metadata[providerSettlementMetaSourceAmount]) == "" {
		metadata[providerSettlementMetaSourceAmount] = strings.TrimSpace(amount.Amount)
	}
	if strings.TrimSpace(metadata[providerSettlementMetaSourceCurrency]) == "" {
		metadata[providerSettlementMetaSourceCurrency] = strings.TrimSpace(amount.Currency)
	}

	sourceWalletRef := ""
	if payment.Intent.Source.ManagedWallet != nil {
		sourceWalletRef = strings.TrimSpace(payment.Intent.Source.ManagedWallet.ManagedWalletRef)
	}
	if sourceWalletRef == "" {
		return rail.TransferRequest{}, merrors.InvalidArgument("provider settlement: source managed wallet is required")
	}

	destRef := ""
	if payment.Intent.Destination.Type == model.EndpointTypeCard {
		if route, err := p.resolveCardRoute(payment.Intent); err == nil {
			destRef = strings.TrimSpace(route.FundingAddress)
		}
	}
	if destRef == "" {
		destRef = paymentRef
	}

	req := rail.TransferRequest{
		OrganizationRef: payment.OrganizationRef.Hex(),
		FromAccountID:   sourceWalletRef,
		ToAccountID:     destRef,
		Currency:        strings.TrimSpace(amount.GetCurrency()),
		Amount:          strings.TrimSpace(amount.GetAmount()),
		IdempotencyKey:  requestID,
		DestinationMemo: paymentRef,
		Metadata:        metadata,
		PaymentRef:      paymentRef,
		OperationRef:    operationRef,
		IntentRef:       intentRef,
	}
	if fromRole != nil {
		req.FromRole = *fromRole
	}
	if toRole != nil {
		req.ToRole = *toRole
	}
	return req, nil
}

func paymentGatewayQuoteRef(payment *model.Payment, quote *orchestratorv1.PaymentQuote) string {
	if quote != nil {
		if ref := strings.TrimSpace(quote.GetQuoteRef()); ref != "" {
			return ref
		}
	}
	if payment != nil && payment.LastQuote != nil {
		return strings.TrimSpace(payment.LastQuote.QuoteRef)
	}
	return ""
}

func paymentGatewayTargetChatID(payment *model.Payment) string {
	if payment == nil {
		return ""
	}
	if payment.Intent.Attributes != nil {
		if chatID := strings.TrimSpace(payment.Intent.Attributes["target_chat_id"]); chatID != "" {
			return chatID
		}
	}
	if payment.Metadata != nil {
		return strings.TrimSpace(payment.Metadata["target_chat_id"])
	}
	return ""
}

func linkProviderSettlementObservation(payment *model.Payment, requestID string) {
	linkRailObservation(payment, model.RailProviderSettlement, requestID, "")
}
