package paymentapiimp

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/server/interface/api/sresponse"
	"go.mongodb.org/mongo-driver/v2/bson"
)

func TestInitiateByQuote_ForwardsClientPaymentRef(t *testing.T) {
	orgRef := bson.NewObjectID()
	exec := &fakeExecutionClientForBatch{}
	api := newBatchAPI(exec)

	body := `{"idempotencyKey":"idem-by-quote","quoteRef":"quote-1","clientPaymentRef":"client-ref-1"}`
	rr := invokeInitiateByQuote(t, api, orgRef, body)
	if got, want := rr.Code, http.StatusOK; got != want {
		t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
	}
	if got, want := len(exec.executeReqs), 1; got != want {
		t.Fatalf("execute calls mismatch: got=%d want=%d", got, want)
	}
	if got, want := exec.executeReqs[0].GetClientPaymentRef(), "client-ref-1"; got != want {
		t.Fatalf("client_payment_ref mismatch: got=%q want=%q", got, want)
	}
}

func TestInitiateByQuote_DoesNotForwardLegacyClientPaymentRefFromMetadata(t *testing.T) {
	orgRef := bson.NewObjectID()
	exec := &fakeExecutionClientForBatch{}
	api := newBatchAPI(exec)

	body := `{"idempotencyKey":"idem-by-quote","quoteRef":"quote-1","metadata":{"client_payment_ref":"legacy-client-ref"}}`
	rr := invokeInitiateByQuote(t, api, orgRef, body)
	if got, want := rr.Code, http.StatusOK; got != want {
		t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
	}
	if got, want := len(exec.executeReqs), 1; got != want {
		t.Fatalf("execute calls mismatch: got=%d want=%d", got, want)
	}
	if got := exec.executeReqs[0].GetClientPaymentRef(); got != "" {
		t.Fatalf("expected empty client_payment_ref, got=%q", got)
	}
}

func TestInitiateByQuote_RejectsMetadataIntentRef(t *testing.T) {
	orgRef := bson.NewObjectID()
	exec := &fakeExecutionClientForBatch{}
	api := newBatchAPI(exec)

	body := `{"idempotencyKey":"idem-by-quote","quoteRef":"quote-1","metadata":{"intent_ref":"legacy-intent"}}`
	rr := invokeInitiateByQuote(t, api, orgRef, body)
	if got, want := rr.Code, http.StatusBadRequest; got != want {
		t.Fatalf("status mismatch: got=%d want=%d body=%s", got, want, rr.Body.String())
	}
	if got := len(exec.executeReqs); got != 0 {
		t.Fatalf("expected no execute calls, got=%d", got)
	}
}

func invokeInitiateByQuote(t *testing.T, api *PaymentAPI, orgRef bson.ObjectID, body string) *httptest.ResponseRecorder {
	t.Helper()

	req := httptest.NewRequestWithContext(context.Background(), http.MethodPost, "/by-quote", bytes.NewBufferString(body))
	routeCtx := chi.NewRouteContext()
	routeCtx.URLParams.Add("organizations_ref", orgRef.Hex())
	req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, routeCtx))

	rr := httptest.NewRecorder()
	handler := api.initiateByQuote(req, &model.Account{}, &sresponse.TokenData{
		Token:      "token",
		Expiration: time.Now().UTC().Add(time.Hour),
	})
	handler.ServeHTTP(rr, req)
	return rr
}
