// Acordate que la transaccion tiene que tener un tipo Intra Wallets y la transaccion que se
  // guarda en la loss lleva el Exchange rate en cero
  // hay q ver si no puede completar la transaccion de avisar con una notificacion
  @Override
  public void sendToWallet(
      String txHash, // ESTE TX HASH PARA QUE SERIA?
      long cryptoAmount,
      String notes,
      Actors actortype,
      ReferenceWallet reference_wallet_sending,
      ReferenceWallet reference_wallet_receiving,
      String wallet_public_key_sending,
      String wallet_public_key_receiving,
      BlockchainNetworkType blockchainNetworkType)
      throws CantSendTransactionException, TransferIntraWalletUsersNotEnoughFundsException {

    Long initialBalance = null;

    UUID id = UUID.randomUUID();

    try {

      // Register the new transaction
      dao.registerNewTransaction(
          id,
          txHash,
          cryptoAmount,
          notes,
          actortype,
          reference_wallet_sending,
          reference_wallet_receiving,
          wallet_public_key_sending,
          wallet_public_key_receiving,
          TransactionState.NEW,
          blockchainNetworkType);

      TransferIntraWalletUsersWrapper transferIntraWalletUsersWrapper = dao.getTransaction(id);

      // DEBIT TO WALLET SENDING

      switch (reference_wallet_sending) {
        case BASIC_WALLET_BITCOIN_WALLET:

          // Consult current balance of the sending wallet

          BitcoinWalletWallet bitcoinWalletWallet =
              this.bitcoinWalletManager.loadWallet(wallet_public_key_sending);
          initialBalance =
              bitcoinWalletWallet
                  .getBalance(BalanceType.AVAILABLE)
                  .getBalance(blockchainNetworkType);

          // Checks the balance of the debiting wallet in order to decide if to continue or not.

          if (initialBalance != null && initialBalance >= cryptoAmount) {

            // Prepares the record to be used within transactions

            // TODO: los actors de estas transacciones van a ser la wallets, hay que distinguir
            // esto con el actor type para poder mostrar despues bien el que seria el contacto
            // asociado
            BitcoinWalletTransactionRecord bitcoinWalletTransactionWalletRecord =
                buildBitcoinWalletRecord(
                    id,
                    new CryptoAddress("", CryptoCurrency.BITCOIN),
                    null,
                    cryptoAmount,
                    new CryptoAddress("", CryptoCurrency.BITCOIN),
                    notes,
                    System.currentTimeMillis(),
                    "",
                    wallet_public_key_sending,
                    wallet_public_key_receiving,
                    actortype,
                    actortype,
                    blockchainNetworkType);

            bitcoinWalletWallet
                .getBalance(BalanceType.BOOK)
                .debit(bitcoinWalletTransactionWalletRecord);
            bitcoinWalletWallet
                .getBalance(BalanceType.AVAILABLE)
                .debit(bitcoinWalletTransactionWalletRecord);

            // Proceeds to credit in the destination wallet
            try {
              receivedToWallet(
                  id,
                  txHash,
                  cryptoAmount,
                  notes,
                  actortype,
                  reference_wallet_sending,
                  reference_wallet_receiving,
                  wallet_public_key_sending,
                  wallet_public_key_receiving,
                  blockchainNetworkType);
            } catch (CantReceiveWalletTransactionException e) {
              // change transaction state to reversed and update balance to revert
              bitcoinWalletWallet.revertTransaction(bitcoinWalletTransactionWalletRecord, false);
              dao.setToError(transferIntraWalletUsersWrapper);
              broadcaster.publish(
                  BroadcasterType.NOTIFICATION_SERVICE,
                  wallet_public_key_sending,
                  "TRANSACTIONWALLETREVERSE");

              throw new CantSendTransactionException(
                  "I could not send the transaction",
                  e,
                  "TransferIntraWalletUsersModuleManager",
                  "Recived Wallet process error");
            }

            // process oK
            dao.setToCompleted(transferIntraWalletUsersWrapper);

          } else {
            broadcaster.publish(
                BroadcasterType.NOTIFICATION_SERVICE,
                wallet_public_key_sending,
                "TRANSACTIONWALLETREVERSE");
            // change transaction state to error
            dao.setToError(transferIntraWalletUsersWrapper);
            // There are not enough funds to perform this transaction
            throw new TransferIntraWalletUsersNotEnoughFundsException(
                "There are not enough funds to perform this transaction",
                null,
                "",
                "NotEnoughFunds");
          }

          break;
        case BASIC_WALLET_DISCOUNT_WALLET:
          break;
        case BASIC_WALLET_FIAT_WALLET:
          break;
        case BASIC_WALLET_LOSS_PROTECTED_WALLET:
          BitcoinLossProtectedWallet bitcoinLossProtectedWallet =
              this.bitcoinLossWalletManager.loadWallet(wallet_public_key_sending);
          // consult current balance of the sending wallet
          initialBalance =
              bitcoinLossProtectedWallet
                  .getBalance(BalanceType.AVAILABLE)
                  .getBalance(blockchainNetworkType);

          // Checks the balance of the debiting wallet in order to decide if to continue or not.

          if (initialBalance != null && initialBalance >= cryptoAmount) {

            // Prepares the record to be used within transactions

            BitcoinLossProtectedWalletTransactionRecord
                bitcoinLossProtectedWalletTransactionWalletRecord2 =
                    buildLossWalletRecord(
                        id,
                        new CryptoAddress("", CryptoCurrency.BITCOIN),
                        null,
                        cryptoAmount,
                        new CryptoAddress("", CryptoCurrency.BITCOIN),
                        notes,
                        System.currentTimeMillis(),
                        "",
                        "",
                        "",
                        actortype,
                        actortype,
                        blockchainNetworkType);

            bitcoinLossProtectedWallet
                .getBalance(BalanceType.BOOK)
                .debit(bitcoinLossProtectedWalletTransactionWalletRecord2);
            bitcoinLossProtectedWallet
                .getBalance(BalanceType.AVAILABLE)
                .debit(bitcoinLossProtectedWalletTransactionWalletRecord2);

            try {
              receivedToWallet(
                  id,
                  txHash,
                  cryptoAmount,
                  notes,
                  actortype,
                  reference_wallet_sending,
                  reference_wallet_receiving,
                  wallet_public_key_sending,
                  wallet_public_key_receiving,
                  blockchainNetworkType);

            } catch (CantReceiveWalletTransactionException e) {

              bitcoinLossProtectedWallet.revertTransaction(
                  bitcoinLossProtectedWalletTransactionWalletRecord2, false);
              broadcaster.publish(
                  BroadcasterType.NOTIFICATION_SERVICE,
                  wallet_public_key_sending,
                  "TRANSACTIONWALLETREVERSE");

              dao.setToError(transferIntraWalletUsersWrapper);
              throw new CantSendTransactionException(
                  "I could not send the transaction",
                  e,
                  "TransferIntraWalletUsersModuleManager",
                  "Recived Wallet process error");
            }

            // process oK
            dao.setToCompleted(transferIntraWalletUsersWrapper);

          } else {
            dao.setToError(transferIntraWalletUsersWrapper);
            // There are not enough funds to perform this transaction
            broadcaster.publish(
                BroadcasterType.NOTIFICATION_SERVICE,
                wallet_public_key_sending,
                "TRANSACTIONWALLETREVERSE");

            throw new TransferIntraWalletUsersNotEnoughFundsException(
                "There are not enough funds to perform this transaction",
                null,
                "",
                "NotEnoughFunds");
          }

          break;
        case COMPOSITE_WALLET_MULTI_ACCOUNT:
          break;
      }

    } catch (CantLoadWalletException e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          e,
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");

    } catch (TransferIntraWalletUsersCantInsertRecordException e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          e,
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");
    } catch (CantCalculateBalanceException e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          e,
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");
    } catch (CantLoadWalletsException e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          e,
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");
    } catch (InvalidParameterException e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          e,
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");
    } catch (CantLoadTableToMemoryException e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          e,
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");
    } catch (Exception e) {
      throw new CantSendTransactionException(
          "I could not send the transaction",
          FermatException.wrapException(e),
          "TransferIntraWalletUsersModuleManager",
          "unknown reason");
    }
  }
  private void receivedToWallet(
      UUID id,
      String txHash,
      long cryptoAmount,
      String notes,
      Actors actortype,
      ReferenceWallet reference_wallet_sending,
      ReferenceWallet reference_wallet_receiving,
      String wallet_public_key_sending,
      String wallet_public_key_receiving,
      BlockchainNetworkType blockchainNetworkType)
      throws CantReceiveWalletTransactionException {

    try {
      TransferIntraWalletUsersWrapper transactionWrapper = dao.getTransaction(id);

      // checks what is the corresponding wallet to be debited.
      switch (reference_wallet_receiving) {
        case BASIC_WALLET_BITCOIN_WALLET:

          // Prepares the record to be used within transactions

          BitcoinWalletTransactionWalletRecord bitcoinWalletTransactionWalletRecord2 =
              buildBitcoinWalletRecord(
                  id,
                  new CryptoAddress("", CryptoCurrency.BITCOIN),
                  null,
                  cryptoAmount,
                  new CryptoAddress("", CryptoCurrency.BITCOIN),
                  notes,
                  System.currentTimeMillis(),
                  "",
                  wallet_public_key_sending,
                  wallet_public_key_receiving,
                  actortype,
                  actortype,
                  blockchainNetworkType);

          BitcoinWalletWallet bitcoinWalletWallet =
              this.bitcoinWalletManager.loadWallet(wallet_public_key_receiving);

          try {
            bitcoinWalletWallet
                .getBalance(BalanceType.AVAILABLE)
                .credit(bitcoinWalletTransactionWalletRecord2);

          } catch (CantRegisterCreditException e) {
            throw new CantReceiveWalletTransactionException(
                CantReceiveWalletTransactionException.DEFAULT_MESSAGE,
                FermatException.wrapException(e),
                "",
                "");
          }
          try {
            bitcoinWalletWallet
                .getBalance(BalanceType.BOOK)
                .credit(bitcoinWalletTransactionWalletRecord2);
          } catch (CantRegisterCreditException e) {
            bitcoinWalletWallet
                .getBalance(BalanceType.AVAILABLE)
                .debit(bitcoinWalletTransactionWalletRecord2);
            throw new CantReceiveWalletTransactionException(
                CantReceiveWalletTransactionException.DEFAULT_MESSAGE,
                FermatException.wrapException(e),
                "",
                "");
          }
          break;
        case BASIC_WALLET_DISCOUNT_WALLET:
          break;
        case BASIC_WALLET_FIAT_WALLET:
          break;
        case BASIC_WALLET_LOSS_PROTECTED_WALLET:
          // Prepares the record to be used within transactions
          BitcoinLossProtectedWallet bitcoinLossProtectedWallet =
              this.bitcoinLossWalletManager.loadWallet(wallet_public_key_receiving);
          BitcoinLossProtectedWalletTransactionRecord
              bitcoinLossProtectedWalletTransactionWalletRecord =
                  buildLossWalletRecord(
                      id,
                      new CryptoAddress("", CryptoCurrency.BITCOIN),
                      null,
                      cryptoAmount,
                      new CryptoAddress("", CryptoCurrency.BITCOIN),
                      notes,
                      System.currentTimeMillis(),
                      "",
                      wallet_public_key_sending,
                      wallet_public_key_receiving,
                      actortype,
                      actortype,
                      blockchainNetworkType);

          try {
            bitcoinLossProtectedWallet
                .getBalance(BalanceType.AVAILABLE)
                .credit(bitcoinLossProtectedWalletTransactionWalletRecord);

          } catch (CantRegisterCreditException e) {
            throw new CantReceiveWalletTransactionException(
                CantReceiveWalletTransactionException.DEFAULT_MESSAGE,
                FermatException.wrapException(e),
                "",
                "");
          }
          try {
            bitcoinLossProtectedWallet
                .getBalance(BalanceType.BOOK)
                .credit(bitcoinLossProtectedWalletTransactionWalletRecord);
          } catch (CantRegisterCreditException e) {
            bitcoinLossProtectedWallet
                .getBalance(BalanceType.AVAILABLE)
                .debit(bitcoinLossProtectedWalletTransactionWalletRecord);
            throw new CantReceiveWalletTransactionException(
                CantReceiveWalletTransactionException.DEFAULT_MESSAGE,
                FermatException.wrapException(e),
                "",
                "");
          }
          break;
      }
    } catch (CantLoadTableToMemoryException e) {
      throw new CantReceiveWalletTransactionException(
          CantReceiveWalletTransactionException.DEFAULT_MESSAGE, e, "", "");
    } catch (InvalidParameterException e) {
      throw new CantReceiveWalletTransactionException(
          CantReceiveWalletTransactionException.DEFAULT_MESSAGE, e, "", "");
    } catch (CantLoadWalletException e) {
      throw new CantReceiveWalletTransactionException(
          CantReceiveWalletTransactionException.DEFAULT_MESSAGE, e, "", "");
    } catch (CantLoadWalletsException e) {
      throw new CantReceiveWalletTransactionException(
          CantReceiveWalletTransactionException.DEFAULT_MESSAGE, e, "", "");
    } catch (Exception e) {
      throw new CantReceiveWalletTransactionException(
          CantReceiveWalletTransactionException.DEFAULT_MESSAGE,
          FermatException.wrapException(e),
          "",
          "");
    }
  }