{-# LANGUAGE RankNTypes #-}
module Cardano.Wallet.Kernel.Diffusion (
    WalletDiffusion(..)
  , fromDiffusion
  ) where

import           Universum

import           Pos.Chain.Txp (TxAux)
import           Pos.Core ()
import           Pos.Infra.Communication.Types.Protocol (NodeId)
import           Pos.Infra.Diffusion.Subscription.Status (SubscriptionStatus,
                     ssMap)
import           Pos.Infra.Diffusion.Types

-- | Wallet diffusion layer
--
-- Limited diffusion that the active wallet needs
--
-- This has two design objectives:
--
-- * We should be able to easily instantiate this from the unit tests
--   (with some kind of mock diffusion layer)
-- * We should be able to translate @Diffusion m@ into @WalletDiffusion@ for
--   any @m@ that we can lower to @IO@ (to isolate us from the specific monad
--   stacks that are used in the full node).
--
-- Note that the latter requirement implies avoiding functionality from the full
-- diffusion layer with negative occurrences of the monad parameter.
data WalletDiffusion = WalletDiffusion {
      -- | Submit a transaction to the network
      walletSendTx                :: TxAux -> IO Bool

      -- | Get subscription status (needed for the node settings endpoint)
    , walletGetSubscriptionStatus :: IO (Map NodeId SubscriptionStatus)
    }

-- | Extract necessary functionality from the full diffusion layer
fromDiffusion :: (forall a. m a -> IO a)
              -> Diffusion m
              -> WalletDiffusion
fromDiffusion nat d = WalletDiffusion {
      walletSendTx                = nat . sendTx d
    , walletGetSubscriptionStatus = readTVarIO $ ssMap (subscriptionStates d)
    }
