package paymentapiimp

import (
	"testing"

	"github.com/tech/sendico/pkg/mservice"
	documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
	connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
	endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
	orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
	quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
	"go.mongodb.org/mongo-driver/v2/bson"
)

func TestOperationDocumentRequest_UsesStructuredOperationFieldsOnly(t *testing.T) {
	op := &connectorv1.Operation{
		OperationRef: "pay-123:hop_1",
		Type:         connectorv1.OperationType_TRANSFER,
		Status:       connectorv1.OperationStatus_OPERATION_SUCCESS,
		Money: &moneyv1.Money{
			Amount:   "100.50",
			Currency: "USDT",
		},
	}

	req := operationDocumentRequest("org-1", mservice.ChainGateway, "requested-op", "pay-123", op)
	if req == nil {
		t.Fatalf("expected request")
	}

	if got, want := req.GetPaymentRef(), "pay-123"; got != want {
		t.Fatalf("payment_ref mismatch: got=%q want=%q", got, want)
	}
	if got := req.GetClientName(); got != "" {
		t.Fatalf("expected empty client_name from operation-only request, got=%q", got)
	}
	if got := req.GetClientAddress(); got != "" {
		t.Fatalf("expected empty client_address from operation-only request, got=%q", got)
	}
}

func TestOperationDocumentRequest_FailureCodeFromStructuredStatus(t *testing.T) {
	req := operationDocumentRequest("org-1", mservice.ChainGateway, "op", "pay-123", &connectorv1.Operation{
		OperationRef: "pay-123:hop_1",
		Type:         connectorv1.OperationType_TRANSFER,
		Status:       connectorv1.OperationStatus_OPERATION_FAILED,
	})
	if req == nil {
		t.Fatalf("expected request")
	}

	if got, want := req.GetFailureCode(), "OPERATION_FAILED"; got != want {
		t.Fatalf("failure_code mismatch: got=%q want=%q", got, want)
	}
}

func TestPaymentClientName_FromIntentComment(t *testing.T) {
	payment := &orchestrationv2.Payment{
		IntentSnapshot: &quotationv2.QuoteIntent{
			Comment: "Jane Customer",
		},
	}

	if got, want := paymentClientName(payment), "Jane Customer"; got != want {
		t.Fatalf("paymentClientName mismatch: got=%q want=%q", got, want)
	}
}

func TestPaymentClientName_FromStructuredCardEndpoint(t *testing.T) {
	raw, err := bson.Marshal(map[string]string{
		"firstName": "Jane",
		"lastName":  "Doe",
	})
	if err != nil {
		t.Fatalf("Marshal: %v", err)
	}

	payment := &orchestrationv2.Payment{
		IntentSnapshot: &quotationv2.QuoteIntent{
			Destination: &endpointv1.PaymentEndpoint{
				Source: &endpointv1.PaymentEndpoint_PaymentMethod{
					PaymentMethod: &endpointv1.PaymentMethod{
						Type: endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD,
						Data: raw,
					},
				},
			},
		},
	}

	if got, want := paymentClientName(payment), "Jane Doe"; got != want {
		t.Fatalf("paymentClientName mismatch: got=%q want=%q", got, want)
	}
}

func TestEnrichOperationDocumentRequestFromPayment_SetsClientName(t *testing.T) {
	req := &documentsv1.GetOperationDocumentRequest{
		OperationRef: "pay-123:hop_1",
	}

	payment := &orchestrationv2.Payment{
		PaymentRef: "pay-123",
		IntentSnapshot: &quotationv2.QuoteIntent{
			Comment: "Client Name",
		},
	}

	enrichOperationDocumentRequestFromPayment(req, payment)
	if got, want := req.GetPaymentRef(), "pay-123"; got != want {
		t.Fatalf("payment_ref mismatch: got=%q want=%q", got, want)
	}
	if got, want := req.GetClientName(), "Client Name"; got != want {
		t.Fatalf("client_name mismatch: got=%q want=%q", got, want)
	}
}

func TestOperationDocumentRequest_Compatibility(t *testing.T) {
	var _ = operationDocumentRequest("org-1", mservice.ChainGateway, "op", "pay-1", &connectorv1.Operation{})
}
