package paymentapiimp

import (
	"net/http"
	"strings"

	"github.com/tech/sendico/pkg/api/http/response"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/pkg/mutil/mzap"
	orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
	"github.com/tech/sendico/server/interface/api/sresponse"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
)

func (a *PaymentAPI) getPayment(r *http.Request, account *model.Account, token *sresponse.TokenData) http.HandlerFunc {
	paymentRef := strings.TrimSpace(a.pph.GetID(r))
	if paymentRef == "" {
		return response.BadReference(a.logger, a.Name(), a.pph.Name(), a.pph.GetID(r), merrors.InvalidArgument("payment reference is required"))
	}

	resp, err := a.execution.GetPayment(r.Context(), &orchestrationv2.GetPaymentRequest{
		PaymentRef: paymentRef,
	})
	if err != nil {
		a.logger.Warn("Failed to fetch payment", zap.Error(err), zap.String("payment_ref", paymentRef))
		return grpcErrorResponse(a.logger, a.Name(), err)
	}
	if resp == nil || resp.GetPayment() == nil {
		return response.Auto(a.logger, a.Name(), merrors.NoData("payment not found"))
	}

	orgRefRaw := strings.TrimSpace(resp.GetOrganizationRef())
	orgRef, err := bson.ObjectIDFromHex(orgRefRaw)
	if err != nil {
		a.logger.Warn("Payment lookup returned invalid organization reference", zap.Error(err), zap.String("organization_ref", orgRefRaw), zap.String("payment_ref", paymentRef))
		return response.Internal(a.logger, a.Name(), merrors.DataConflict("payment lookup returned invalid organization reference"))
	}

	allowed, err := a.enf.Enforce(r.Context(), a.permissionRef, account.ID, orgRef, bson.NilObjectID, model.ActionRead)
	if err != nil {
		a.logger.Warn("Failed to check payment access permissions", zap.Error(err), mzap.ObjRef("organization_ref", orgRef), zap.String("payment_ref", paymentRef))
		return response.Auto(a.logger, a.Name(), err)
	}
	if !allowed {
		a.logger.Debug("Payment access denied, hiding existence", mzap.ObjRef("organization_ref", orgRef), zap.String("payment_ref", paymentRef))
		return response.NotFound(a.logger, a.Name(), "payment not found")
	}

	return sresponse.PaymentResponse(a.logger, resp.GetPayment(), token)
}
