package paymentapiimp

import (
	"testing"

	paymenttypes "github.com/tech/sendico/pkg/payments/types"
	fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
	paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
	quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
	"github.com/tech/sendico/server/interface/api/srequest"
)

func TestMapQuoteIntent_PropagatesFeeTreatment(t *testing.T) {
	source, err := srequest.NewManagedWalletEndpointDTO(srequest.ManagedWalletEndpoint{
		ManagedWalletRef: "wallet-source-1",
	}, nil)
	if err != nil {
		t.Fatalf("failed to build source endpoint: %v", err)
	}

	destination, err := srequest.NewCardEndpointDTO(srequest.CardEndpoint{
		Pan:       "2200700142860161",
		FirstName: "John",
		LastName:  "Doe",
		ExpMonth:  3,
		ExpYear:   2030,
	}, nil)
	if err != nil {
		t.Fatalf("failed to build destination endpoint: %v", err)
	}

	intent := &srequest.PaymentIntent{
		Kind:           srequest.PaymentKindPayout,
		Source:         &source,
		Destination:    &destination,
		Amount:         &paymenttypes.Money{Amount: "10", Currency: "USDT"},
		SettlementMode: srequest.SettlementModeFixReceived,
		FeeTreatment:   srequest.FeeTreatmentDeductFromDestination,
	}

	got, err := mapQuoteIntent(intent)
	if err != nil {
		t.Fatalf("mapQuoteIntent returned error: %v", err)
	}
	if got == nil {
		t.Fatalf("expected mapped quote intent")
	}
	if got.GetFeeTreatment() != quotationv2.FeeTreatment_FEE_TREATMENT_DEDUCT_FROM_DESTINATION {
		t.Fatalf("unexpected fee treatment: got=%s", got.GetFeeTreatment().String())
	}
}

func TestMapQuoteIntent_InvalidFeeTreatmentFails(t *testing.T) {
	source, err := srequest.NewManagedWalletEndpointDTO(srequest.ManagedWalletEndpoint{
		ManagedWalletRef: "wallet-source-1",
	}, nil)
	if err != nil {
		t.Fatalf("failed to build source endpoint: %v", err)
	}

	destination, err := srequest.NewCardEndpointDTO(srequest.CardEndpoint{
		Pan:       "2200700142860161",
		FirstName: "John",
		LastName:  "Doe",
		ExpMonth:  3,
		ExpYear:   2030,
	}, nil)
	if err != nil {
		t.Fatalf("failed to build destination endpoint: %v", err)
	}

	intent := &srequest.PaymentIntent{
		Kind:           srequest.PaymentKindPayout,
		Source:         &source,
		Destination:    &destination,
		Amount:         &paymenttypes.Money{Amount: "10", Currency: "USDT"},
		SettlementMode: srequest.SettlementModeFixSource,
		FeeTreatment:   srequest.FeeTreatment("wrong_value"),
	}

	if _, err := mapQuoteIntent(intent); err == nil {
		t.Fatalf("expected error for invalid fee treatment")
	}
}

func TestMapQuoteIntent_AcceptsIndependentSettlementAndFeeTreatment(t *testing.T) {
	source, err := srequest.NewManagedWalletEndpointDTO(srequest.ManagedWalletEndpoint{
		ManagedWalletRef: "wallet-source-1",
	}, nil)
	if err != nil {
		t.Fatalf("failed to build source endpoint: %v", err)
	}

	destination, err := srequest.NewCardEndpointDTO(srequest.CardEndpoint{
		Pan:       "2200700142860161",
		FirstName: "John",
		LastName:  "Doe",
		ExpMonth:  3,
		ExpYear:   2030,
	}, nil)
	if err != nil {
		t.Fatalf("failed to build destination endpoint: %v", err)
	}

	intent := &srequest.PaymentIntent{
		Kind:           srequest.PaymentKindPayout,
		Source:         &source,
		Destination:    &destination,
		Amount:         &paymenttypes.Money{Amount: "10", Currency: "USDT"},
		SettlementMode: srequest.SettlementModeFixReceived,
		FeeTreatment:   srequest.FeeTreatmentAddToSource,
	}

	got, err := mapQuoteIntent(intent)
	if err != nil {
		t.Fatalf("mapQuoteIntent returned error: %v", err)
	}
	if got.GetSettlementMode() != paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED {
		t.Fatalf("unexpected settlement mode: got=%s", got.GetSettlementMode().String())
	}
	if got.GetFeeTreatment() != quotationv2.FeeTreatment_FEE_TREATMENT_ADD_TO_SOURCE {
		t.Fatalf("unexpected fee treatment: got=%s", got.GetFeeTreatment().String())
	}
}

func TestMapQuoteIntent_DerivesSettlementCurrencyFromAmountWithoutFX(t *testing.T) {
	source, err := srequest.NewManagedWalletEndpointDTO(srequest.ManagedWalletEndpoint{
		ManagedWalletRef: "wallet-source-1",
	}, nil)
	if err != nil {
		t.Fatalf("failed to build source endpoint: %v", err)
	}

	destination, err := srequest.NewCardEndpointDTO(srequest.CardEndpoint{
		Pan:       "2200700142860161",
		FirstName: "John",
		LastName:  "Doe",
		ExpMonth:  3,
		ExpYear:   2030,
	}, nil)
	if err != nil {
		t.Fatalf("failed to build destination endpoint: %v", err)
	}

	intent := &srequest.PaymentIntent{
		Kind:           srequest.PaymentKindPayout,
		Source:         &source,
		Destination:    &destination,
		Amount:         &paymenttypes.Money{Amount: "10", Currency: "USDT"},
		SettlementMode: srequest.SettlementModeFixSource,
		FeeTreatment:   srequest.FeeTreatmentAddToSource,
	}

	got, err := mapQuoteIntent(intent)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got.GetSettlementCurrency() != "USDT" {
		t.Fatalf("unexpected settlement currency: got=%q", got.GetSettlementCurrency())
	}
}

func TestMapQuoteIntent_DerivesSettlementCurrencyFromFX(t *testing.T) {
	source, err := srequest.NewManagedWalletEndpointDTO(srequest.ManagedWalletEndpoint{
		ManagedWalletRef: "wallet-source-1",
	}, nil)
	if err != nil {
		t.Fatalf("failed to build source endpoint: %v", err)
	}

	destination, err := srequest.NewCardEndpointDTO(srequest.CardEndpoint{
		Pan:       "2200700142860161",
		FirstName: "John",
		LastName:  "Doe",
		ExpMonth:  3,
		ExpYear:   2030,
	}, nil)
	if err != nil {
		t.Fatalf("failed to build destination endpoint: %v", err)
	}

	intent := &srequest.PaymentIntent{
		Kind:           srequest.PaymentKindPayout,
		Source:         &source,
		Destination:    &destination,
		Amount:         &paymenttypes.Money{Amount: "10", Currency: "USDT"},
		SettlementMode: srequest.SettlementModeFixSource,
		FeeTreatment:   srequest.FeeTreatmentAddToSource,
		FX: &srequest.FXIntent{
			Pair: &srequest.CurrencyPair{
				Base:  "USDT",
				Quote: "RUB",
			},
			Side: srequest.FXSideSellBaseBuyQuote,
		},
	}

	got, err := mapQuoteIntent(intent)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got.GetSettlementCurrency() != "RUB" {
		t.Fatalf("unexpected settlement currency: got=%q", got.GetSettlementCurrency())
	}
	if got.GetFx() == nil || got.GetFx().GetPair() == nil {
		t.Fatalf("expected fx intent")
	}
	if got.GetFx().GetSide() != fxv1.Side_SELL_BASE_BUY_QUOTE {
		t.Fatalf("unexpected fx side: got=%s", got.GetFx().GetSide().String())
	}
	if got.GetFx().GetPair().GetBase() != "USDT" || got.GetFx().GetPair().GetQuote() != "RUB" {
		t.Fatalf("unexpected fx pair: got=%s/%s", got.GetFx().GetPair().GetBase(), got.GetFx().GetPair().GetQuote())
	}
}

func TestMapQuoteIntent_PropagatesFXSideBuyBaseSellQuote(t *testing.T) {
	source, err := srequest.NewManagedWalletEndpointDTO(srequest.ManagedWalletEndpoint{
		ManagedWalletRef: "wallet-source-1",
	}, nil)
	if err != nil {
		t.Fatalf("failed to build source endpoint: %v", err)
	}

	destination, err := srequest.NewCardEndpointDTO(srequest.CardEndpoint{
		Pan:       "2200700142860161",
		FirstName: "John",
		LastName:  "Doe",
		ExpMonth:  3,
		ExpYear:   2030,
	}, nil)
	if err != nil {
		t.Fatalf("failed to build destination endpoint: %v", err)
	}

	intent := &srequest.PaymentIntent{
		Kind:           srequest.PaymentKindPayout,
		Source:         &source,
		Destination:    &destination,
		Amount:         &paymenttypes.Money{Amount: "10", Currency: "USDT"},
		SettlementMode: srequest.SettlementModeFixSource,
		FeeTreatment:   srequest.FeeTreatmentAddToSource,
		FX: &srequest.FXIntent{
			Pair: &srequest.CurrencyPair{
				Base:  "RUB",
				Quote: "USDT",
			},
			Side: srequest.FXSideBuyBaseSellQuote,
		},
	}

	got, err := mapQuoteIntent(intent)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got.GetFx() == nil || got.GetFx().GetPair() == nil {
		t.Fatalf("expected fx intent")
	}
	if got.GetFx().GetSide() != fxv1.Side_BUY_BASE_SELL_QUOTE {
		t.Fatalf("unexpected fx side: got=%s", got.GetFx().GetSide().String())
	}
	if got.GetSettlementCurrency() != "RUB" {
		t.Fatalf("unexpected settlement currency: got=%q", got.GetSettlementCurrency())
	}
}
