content: {-# LANGUAGE RecordWildCards #-}
  
  module Statistics.Report
      ( reportTxFate
      ) where
  
  import           Data.Map.Strict (Map)
  import qualified Data.Map.Strict as M
  import qualified Data.Set as S
  import qualified Data.Text as T
  import           System.IO (hPutStrLn)
  
  import           Statistics.Block (TxFate (..))
  import           Types
  import           Universum
  
  reportTxFate :: FilePath -> Map TxHash TxFate -> IO ([TxHash], [TxHash], [TxHash])
  reportTxFate f m = withFile f WriteMode $ \h -> do
      let total = M.size m
          m'    = M.filter isFork m
          fork  = M.size m'
          m''   = M.filter isChain m
          chain = M.size m''
          m'''  = M.filter isLost m
          lost  = M.size m'''
          chains = fst <$> M.toList m''
          forks  = fst <$> M.toList m'
          losts  = fst <$> M.toList m'''
      hPutStrLn h $ "total transactions: " ++ show total
      hPutStrLn h $ "in blockchain: " ++ show chain
      hPutStrLn h $ "in fork: " ++ show fork
      hPutStrLn h $ "lost: " ++ show lost
      hPutStrLn h ""
      hPutStrLn h "transactions in blockchain:"
      for_ (M.toList m'') $ \(tx, InBlockChain _ hash _) ->
          hPutStrLn h $ toString tx ++ ": " ++ toString (T.take 6 hash)
      hPutStrLn h ""
      hPutStrLn h "transactions in fork:"
      for_ (M.toList m') $ \(tx, InFork s) ->
          hPutStrLn h $ toString tx ++ ": " ++ toString (unwords $ map (T.take 6 . snd) $ S.toList s)
      hPutStrLn h ""
      hPutStrLn h "lost transactions:"
      for_ (M.toList m''') $ \(tx, InNoBlock) ->
          hPutStrLn h (toString tx)
      return (chains, forks, losts)
  
  isFork :: TxFate -> Bool
  isFork (InFork _) = True
  isFork _          = False
  
  isLost :: TxFate -> Bool
  isLost InNoBlock = True
  isLost _         = False
  
  isChain :: TxFate -> Bool
  isChain (InBlockChain{}) = True
  isChain _                = False
  