-- | This module exposes the various events emitted during a mockchain run.
module Cooked.MockChain.Journal where

import Cooked.MockChain.Log
import Cooked.Pretty.Class
import Cooked.Pretty.Options
import Data.Map
import Data.Map qualified as Map
import PlutusLedgerApi.V3 qualified as Api

-- | This represents the writable elements that can be emitted throughout a
-- mockchain run.
data MockChainJournal where
  MockChainJournal ::
    { -- | Log entries generated by cooked-validators
      MockChainJournal -> [MockChainLogEntry]
mcbLog :: [MockChainLogEntry],
      -- | Aliases stored by the user
      MockChainJournal -> Map BuiltinByteString String
mcbAliases :: Map Api.BuiltinByteString String,
      -- | Notes taken by the user, parameterized by some pretty cooked options,
      -- to get a better display at the end of the run
      MockChainJournal -> [PrettyCookedOpts -> DocCooked]
mcbNotes :: [PrettyCookedOpts -> DocCooked],
      -- | Assertions gathered during the run, alongside their associated error
      -- messages to display in case of failure
      MockChainJournal -> [(String, Bool)]
mcbAssertions :: [(String, Bool)]
    } ->
    MockChainJournal

instance Semigroup MockChainJournal where
  MockChainJournal [MockChainLogEntry]
l Map BuiltinByteString String
a [PrettyCookedOpts -> DocCooked]
n [(String, Bool)]
p <> :: MockChainJournal -> MockChainJournal -> MockChainJournal
<> MockChainJournal [MockChainLogEntry]
l' Map BuiltinByteString String
a' [PrettyCookedOpts -> DocCooked]
n' [(String, Bool)]
p' =
    [MockChainLogEntry]
-> Map BuiltinByteString String
-> [PrettyCookedOpts -> DocCooked]
-> [(String, Bool)]
-> MockChainJournal
MockChainJournal ([MockChainLogEntry]
l [MockChainLogEntry] -> [MockChainLogEntry] -> [MockChainLogEntry]
forall a. Semigroup a => a -> a -> a
<> [MockChainLogEntry]
l') (Map BuiltinByteString String
a Map BuiltinByteString String
-> Map BuiltinByteString String -> Map BuiltinByteString String
forall a. Semigroup a => a -> a -> a
<> Map BuiltinByteString String
a') ([PrettyCookedOpts -> DocCooked]
n [PrettyCookedOpts -> DocCooked]
-> [PrettyCookedOpts -> DocCooked]
-> [PrettyCookedOpts -> DocCooked]
forall a. Semigroup a => a -> a -> a
<> [PrettyCookedOpts -> DocCooked]
n') ([(String, Bool)]
p [(String, Bool)] -> [(String, Bool)] -> [(String, Bool)]
forall a. Semigroup a => a -> a -> a
<> [(String, Bool)]
p')

instance Monoid MockChainJournal where
  mempty :: MockChainJournal
mempty = [MockChainLogEntry]
-> Map BuiltinByteString String
-> [PrettyCookedOpts -> DocCooked]
-> [(String, Bool)]
-> MockChainJournal
MockChainJournal [MockChainLogEntry]
forall a. Monoid a => a
mempty Map BuiltinByteString String
forall a. Monoid a => a
mempty [PrettyCookedOpts -> DocCooked]
forall a. Monoid a => a
mempty [(String, Bool)]
forall a. Monoid a => a
mempty

-- | Build a `MockChainJournal` from a single log entry
fromLogEntry :: MockChainLogEntry -> MockChainJournal
fromLogEntry :: MockChainLogEntry -> MockChainJournal
fromLogEntry MockChainLogEntry
entry = MockChainJournal
forall a. Monoid a => a
mempty {mcbLog = [entry]}

-- | Build a `MockChainJournal` from a single alias
fromAlias :: String -> Api.BuiltinByteString -> MockChainJournal
fromAlias :: String -> BuiltinByteString -> MockChainJournal
fromAlias String
s BuiltinByteString
hash = MockChainJournal
forall a. Monoid a => a
mempty {mcbAliases = Map.singleton hash s}

-- | Build a `MockChainJournal` from a single note
fromNote :: (PrettyCookedOpts -> DocCooked) -> MockChainJournal
fromNote :: (PrettyCookedOpts -> DocCooked) -> MockChainJournal
fromNote PrettyCookedOpts -> DocCooked
s = MockChainJournal
forall a. Monoid a => a
mempty {mcbNotes = [s]}

-- | Build a `MockChainJournal` from a single assertion and error message
fromAssert :: String -> Bool -> MockChainJournal
fromAssert :: String -> Bool -> MockChainJournal
fromAssert String
s Bool
p = MockChainJournal
forall a. Monoid a => a
mempty {mcbAssertions = [(s, p)]}