// SPDX-FileCopyrightText: © 2026 LEDGER SAS
// SPDX-License-Identifier: Apache-2.0

import { NetworkDown } from '@ledgerhq/errors'
import {
  Memo,
  Operation as StellarSdkOperation,
  Transaction as StellarSdkTransaction,
  xdr,
} from '@stellar/stellar-sdk'
import { getRecipientAccount, loadAccount } from '../network'
import { StellarAssetRequired, StellarMuxedAccountNotExist } from '../types'
import {
  buildChangeTrustOperation,
  buildCreateAccountOperation,
  buildPaymentOperation,
  buildTransactionBuilder,
} from './sdkWrapper'

export async function craftTransaction(
  account: {
    address: string
  },
  transaction: {
    type: string
    recipient: string
    amount: bigint
    fee: bigint
    assetCode?: string | undefined
    assetIssuer?: string | undefined
    memoType?: string | null | undefined
    memoValue?: string | null | undefined
  }
): Promise<{ transaction: StellarSdkTransaction; xdr: string; signatureBase: string }> {
  const { amount, recipient, fee, memoType, memoValue, type, assetCode, assetIssuer } = transaction
  const source = await loadAccount(account.address)

  if (!source) {
    throw new NetworkDown()
  }

  const transactionBuilder = buildTransactionBuilder(source, fee)
  let operation: xdr.Operation<StellarSdkOperation.ChangeTrust> | null = null

  if (type === 'changeTrust') {
    if (!assetCode || !assetIssuer) {
      throw new StellarAssetRequired('')
    }

    operation = buildChangeTrustOperation(assetCode, assetIssuer)
  } else {
    // Payment
    const recipientAccount = await getRecipientAccount({
      recipient,
    })

    if (recipientAccount?.id) {
      operation = buildPaymentOperation({
        destination: recipient,
        amount,
        assetCode,
        assetIssuer,
      })
    } else {
      if (recipientAccount?.isMuxedAccount) {
        throw new StellarMuxedAccountNotExist('')
      }

      operation = buildCreateAccountOperation(recipient, amount)
    }
  }

  transactionBuilder.addOperation(operation)

  const memo = buildMemo(memoType, memoValue)
  if (memo) {
    transactionBuilder.addMemo(memo)
  }

  const craftedTransaction = transactionBuilder.setTimeout(0).build()
  return {
    transaction: craftedTransaction,
    xdr: craftedTransaction.toXDR(),
    signatureBase: craftedTransaction.signatureBase().toString('base64'),
  }
}

function buildMemo(
  memoType?: string | null | undefined,
  memoValue?: string | null | undefined
): Memo | null {
  if (memoType && memoValue) {
    switch (memoType) {
      case 'MEMO_TEXT':
        return Memo.text(memoValue)
      case 'MEMO_ID':
        return Memo.id(memoValue)
      case 'MEMO_HASH':
        return Memo.hash(memoValue)
      case 'MEMO_RETURN':
        return Memo.return(memoValue)
    }
  }
  return null
}
