content: module SharedLogic.Payment where
  
  import qualified Beckn.ACL.Cancel as ACL
  import qualified Data.HashMap.Strict as HM
  import qualified Domain.Action.UI.Cancel as DCancel
  import qualified Domain.Types.Booking as Booking
  import qualified Domain.Types.BookingCancellationReason as SBCR
  import qualified Domain.Types.CancellationReason as SCR
  import qualified Domain.Types.Merchant as Merchant
  import qualified Domain.Types.MerchantOperatingCity as DMOC
  import qualified Domain.Types.Person as Person
  import qualified Domain.Types.Ride as Ride
  import qualified Kernel.External.Payment.Interface as Payment
  import Kernel.Prelude
  import qualified Kernel.Storage.Esqueleto as Esq
  import Kernel.Streaming.Kafka.Producer.Types (HasKafkaProducer, KafkaProducerTools)
  import Kernel.Types.CacheFlow
  import Kernel.Types.Id
  import Kernel.Utils.Common
  import qualified Lib.Payment.Domain.Action as DPayment
  import qualified Lib.Payment.Domain.Types.Common as DPayment
  import qualified SharedLogic.CallBPP as CallBPP
  import Storage.Beam.Payment ()
  import qualified Tools.Payment as TPayment
  import TransactionLogs.Types
  
  makePaymentIntent ::
    ( MonadFlow m,
      EncFlow m r,
      EsqDBFlow m r,
      CacheFlow m r,
      HasShortDurationRetryCfg r c,
      HasKafkaProducer r
    ) =>
    Id Merchant.Merchant ->
    Id DMOC.MerchantOperatingCity ->
    Id Person.Person ->
    Ride.Ride ->
    Payment.CreatePaymentIntentReq ->
    m Payment.CreatePaymentIntentResp
  makePaymentIntent merchantId merchantOpCityId personId ride createPaymentIntentReq = do
    let commonMerchantId = cast @Merchant.Merchant @DPayment.Merchant merchantId
        commonPersonId = cast @Person.Person @DPayment.Person personId
        commonRideId = cast @Ride.Ride @DPayment.Ride ride.id
        createPaymentIntentCall = TPayment.createPaymentIntent merchantId merchantOpCityId
        updatePaymentIntentAmountCall = TPayment.updateAmountInPaymentIntent merchantId merchantOpCityId
        capturePaymentIntentCall = TPayment.capturePaymentIntent merchantId merchantOpCityId
        getPaymentIntentCall = TPayment.getPaymentIntent merchantId merchantOpCityId
    DPayment.createPaymentIntentService commonMerchantId (Just $ cast merchantOpCityId) commonPersonId commonRideId ride.shortId.getShortId createPaymentIntentReq createPaymentIntentCall updatePaymentIntentAmountCall capturePaymentIntentCall getPaymentIntentCall
  
  cancelPaymentIntent ::
    ( MonadFlow m,
      EncFlow m r,
      EsqDBFlow m r,
      CacheFlow m r,
      HasShortDurationRetryCfg r c,
      HasKafkaProducer r
    ) =>
    Id Merchant.Merchant ->
    Id DMOC.MerchantOperatingCity ->
    Id Ride.Ride ->
    m ()
  cancelPaymentIntent merchantId merchantOpCityId rideId = do
    let cancelPaymentIntentCall = TPayment.cancelPaymentIntent merchantId merchantOpCityId
    DPayment.cancelPaymentIntentService (cast @Ride.Ride @DPayment.Ride rideId) cancelPaymentIntentCall
  
  chargePaymentIntent ::
    ( MonadFlow m,
      EncFlow m r,
      EsqDBFlow m r,
      CacheFlow m r,
      HasShortDurationRetryCfg r c,
      HasKafkaProducer r
    ) =>
    Id Merchant.Merchant ->
    Id DMOC.MerchantOperatingCity ->
    Payment.PaymentIntentId ->
    m Bool
  chargePaymentIntent merchantId merchantOpCityId paymentIntentId = do
    let capturePaymentIntentCall = TPayment.capturePaymentIntent merchantId merchantOpCityId
        getPaymentIntentCall = TPayment.getPaymentIntent merchantId merchantOpCityId
    DPayment.chargePaymentIntentService paymentIntentId capturePaymentIntentCall getPaymentIntentCall
  
  paymentErrorHandler ::
    ( EncFlow m r,
      Esq.EsqDBReplicaFlow m r,
      EsqDBFlow m r,
      CacheFlow m r,
      HasFlowEnv m r '["kafkaProducerTools" ::: KafkaProducerTools],
      HasFlowEnv m r '["ondcTokenHashMap" ::: HM.HashMap KeyConfig TokenConfig],
      HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
      HasFlowEnv m r '["nwAddress" ::: BaseUrl],
      HasShortDurationRetryCfg r c,
      HasKafkaProducer r
    ) =>
    Booking.Booking ->
    SomeException ->
    m ()
  paymentErrorHandler booking exec = do
    let err = fromException @Payment.StripeError exec
    cancelBooking err
    where
      cancelBooking err = do
        let req =
              DCancel.CancelReq
                { reasonCode = SCR.CancellationReasonCode (maybe "UNKOWN_ERROR" toErrorCode err),
                  reasonStage = SCR.OnAssign,
                  additionalInfo = err >>= toMessage,
                  reallocate = Nothing,
                  blockOnCancellationRate = Nothing
                }
        dCancelRes <- DCancel.cancel booking Nothing req SBCR.ByApplication
        void $ withShortRetry $ CallBPP.cancelV2 booking.merchantId dCancelRes.bppUrl =<< ACL.buildCancelReqV2 dCancelRes req.reallocate
  
  makeCxCancellationPayment ::
    ( MonadFlow m,
      EncFlow m r,
      EsqDBFlow m r,
      CacheFlow m r,
      HasShortDurationRetryCfg r c,
      HasKafkaProducer r
    ) =>
    Id Merchant.Merchant ->
    Id DMOC.MerchantOperatingCity ->
    Payment.PaymentIntentId ->
    HighPrecMoney ->
    m Bool
  makeCxCancellationPayment merchantId merchantOpCityId paymentIntentId cancellationAmount = do
    let capturePaymentIntentCall = TPayment.capturePaymentIntent merchantId merchantOpCityId
        getPaymentIntentCall = TPayment.getPaymentIntent merchantId merchantOpCityId
    DPayment.updateForCXCancelPaymentIntentService paymentIntentId capturePaymentIntentCall getPaymentIntentCall cancellationAmount
  