import { LND_PATHFINDING_TIME_PREF_PPM, LND_PATHFINDING_TIMEOUT_MS } from '@/lib/constants'
import { msatsToSats, satsToMsats, toPositiveBigInt } from '@/lib/format'
import { Prisma } from '@prisma/client'
import { parsePaymentRequest, payViaPaymentRequest } from 'ln-service'

// paying actions are completely distinct from paid actions
// and there's only one paying action: send
// ... still we want the api to at least be similar
export default async function performPayingAction ({ bolt11, maxFee, walletId }, { me, models, lnd }) {
  try {
    console.group('performPayingAction', `${bolt11.slice(0, 10)}...`, maxFee, walletId)

    if (!me) {
      throw new Error('You must be logged in to perform this action')
    }

    const decoded = await parsePaymentRequest({ request: bolt11 })
    const cost = toPositiveBigInt(toPositiveBigInt(decoded.mtokens) + satsToMsats(maxFee))

    console.log('cost', cost)

    const withdrawal = await models.$transaction(async tx => {
      await tx.user.update({
        where: {
          id: me.id
        },
        data: { msats: { decrement: cost } }
      })

      return await tx.withdrawl.create({
        data: {
          hash: decoded.id,
          bolt11,
          msatsPaying: toPositiveBigInt(decoded.mtokens),
          msatsFeePaying: satsToMsats(maxFee),
          userId: me.id,
          walletId,
          autoWithdraw: !!walletId
        }
      })
    }, { isolationLevel: Prisma.TransactionIsolationLevel.ReadCommitted })

    payViaPaymentRequest({
      lnd,
      request: withdrawal.bolt11,
      max_fee: msatsToSats(withdrawal.msatsFeePaying),
      pathfinding_timeout: LND_PATHFINDING_TIMEOUT_MS,
      confidence: LND_PATHFINDING_TIME_PREF_PPM
    }).catch(console.error)

    return withdrawal
  } catch (e) {
    if (e.message.includes('\\"users\\" violates check constraint \\"msats_positive\\"')) {
      throw new Error('insufficient funds')
    }
    if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
      throw new Error('you cannot withdraw to the same invoice twice')
    }
    console.error('performPayingAction failed', e)
    throw e
  } finally {
    console.groupEnd()
  }
}