{-# LANGUAGE AllowAmbiguousTypes   #-}
{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE DerivingStrategies    #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeOperators         #-}
{-# OPTIONS_GHC -Wno-overlapping-patterns #-}
module Wallet.Emulator.Types(
    -- * Wallets
    Wallet.Emulator.Wallet.Wallet(..),
    Wallet.Emulator.Wallet.WalletId(..),
    Crypto.XPrv,
    Crypto.XPub,
    Wallet.Emulator.Wallet.mockWalletAddress,
    Wallet.Emulator.Wallet.mockWalletPaymentPubKey,
    Wallet.Emulator.Wallet.mockWalletPaymentPubKeyHash,
    Wallet.Emulator.Wallet.knownWallets,
    Wallet.Emulator.Wallet.knownWallet,
    Ledger.CardanoWallet.WalletNumber(..),
    Ledger.CardanoWallet.toWalletNumber,
    Wallet.Emulator.Wallet.fromWalletNumber,
    Ledger.CardanoWallet.MockWallet(..),
    Cardano.Node.Emulator.Internal.Node.TxPool,
    -- * Emulator
    EmulatorEffs,
    Plutus.Contract.Error.AssertionError(..),
    Plutus.Contract.Error.AsAssertionError(..),
    Wallet.Emulator.NodeClient.ChainClientNotification(..),
    Wallet.Emulator.MultiAgent.EmulatorEvent,
    Wallet.Emulator.MultiAgent.EmulatorEvent',
    Wallet.Emulator.MultiAgent.EmulatorTimeEvent(..),
    -- ** Wallet state
    Wallet.Emulator.Wallet.WalletState(..),
    Wallet.Emulator.Wallet.emptyWalletState,
    Wallet.Emulator.Wallet.ownPaymentPrivateKey,
    Wallet.Emulator.Wallet.ownAddress,
    -- ** Traces
    Wallet.Emulator.MultiAgent.walletAction,
    -- * Emulator internals
    Wallet.Emulator.MultiAgent.EmulatorState(..),
    Wallet.Emulator.MultiAgent.emptyEmulatorState,
    Wallet.Emulator.MultiAgent.emulatorState,
    Wallet.Emulator.MultiAgent.emulatorStatePool,
    Wallet.Emulator.MultiAgent.emulatorStateInitialDist,
    Cardano.Node.Emulator.Internal.Node.txPool,
    Wallet.Emulator.MultiAgent.walletStates,
    Cardano.Node.Emulator.Internal.Node.index,
    Wallet.Emulator.MultiAgent.chainState,
    Cardano.Node.Emulator.Internal.Node.chainCurrentSlot,
    processEmulated,
    Wallet.Emulator.MultiAgent.fundsDistribution,
    Wallet.Emulator.MultiAgent.emLog
    ) where

import Cardano.Crypto.Wallet qualified as Crypto
import Control.Lens hiding (index)
import Control.Monad.Freer (Eff, Member, interpret, reinterpret2, type (~>))
import Control.Monad.Freer.Error (Error)
import Control.Monad.Freer.Extras qualified as Eff
import Control.Monad.Freer.Extras.Log (LogMsg, mapLog)
import Control.Monad.Freer.State (State)

import Plutus.ChainIndex (ChainIndexError)
import Wallet.API (WalletAPIError)

import Cardano.Node.Emulator.Internal.Node (ChainControlEffect, ChainEffect, ChainEvent, ChainState, Params,
                                            handleChain, handleControlChain)
import Cardano.Node.Emulator.Internal.Node qualified
import Ledger.CardanoWallet qualified
import Plutus.Contract.Error (AssertionError)
import Plutus.Contract.Error qualified
import Wallet.Emulator.MultiAgent (EmulatorEvent', EmulatorState, MultiAgentControlEffect, MultiAgentEffect, chainEvent,
                                   chainState, handleMultiAgent, handleMultiAgentControl)
import Wallet.Emulator.MultiAgent qualified
import Wallet.Emulator.NodeClient qualified
import Wallet.Emulator.Wallet qualified

type EmulatorEffs = '[MultiAgentEffect, ChainEffect, ChainControlEffect]

processEmulated :: forall effs.
    ( Member (Error WalletAPIError) effs
    , Member (Error ChainIndexError) effs
    , Member (State EmulatorState) effs
    , Member (LogMsg EmulatorEvent') effs
    )
    => Params
    -> Eff (MultiAgentEffect ': MultiAgentControlEffect ': ChainEffect ': ChainControlEffect ': effs)
    ~> Eff effs
processEmulated :: Params
-> Eff
     (MultiAgentEffect
        : MultiAgentControlEffect : ChainEffect : ChainControlEffect
        : effs)
   ~> Eff effs
processEmulated Params
params Eff
  (MultiAgentEffect
     : MultiAgentControlEffect : ChainEffect : ChainControlEffect
     : effs)
  x
act =
    Eff
  (MultiAgentEffect
     : MultiAgentControlEffect : ChainEffect : ChainControlEffect
     : effs)
  x
act
        Eff
  (MultiAgentEffect
     : MultiAgentControlEffect : ChainEffect : ChainControlEffect
     : effs)
  x
-> (Eff
      (MultiAgentEffect
         : MultiAgentControlEffect : ChainEffect : ChainControlEffect
         : effs)
      x
    -> Eff
         (MultiAgentControlEffect : ChainEffect : ChainControlEffect : effs)
         x)
-> Eff
     (MultiAgentControlEffect : ChainEffect : ChainControlEffect : effs)
     x
forall a b. a -> (a -> b) -> b
& Eff
  (MultiAgentEffect
     : MultiAgentControlEffect : ChainEffect : ChainControlEffect
     : effs)
  x
-> Eff
     (MultiAgentControlEffect : ChainEffect : ChainControlEffect : effs)
     x
forall (effs :: [* -> *]).
Members MultiAgentEffs effs =>
Eff (MultiAgentEffect : effs) ~> Eff effs
handleMultiAgent
        Eff
  (MultiAgentControlEffect : ChainEffect : ChainControlEffect : effs)
  x
-> (Eff
      (MultiAgentControlEffect : ChainEffect : ChainControlEffect : effs)
      x
    -> Eff (ChainEffect : ChainControlEffect : effs) x)
-> Eff (ChainEffect : ChainControlEffect : effs) x
forall a b. a -> (a -> b) -> b
& Eff
  (MultiAgentControlEffect : ChainEffect : ChainControlEffect : effs)
  x
-> Eff (ChainEffect : ChainControlEffect : effs) x
forall (effs :: [* -> *]).
Members MultiAgentEffs effs =>
Eff (MultiAgentControlEffect : effs) ~> Eff effs
handleMultiAgentControl
        Eff (ChainEffect : ChainControlEffect : effs) x
-> (Eff (ChainEffect : ChainControlEffect : effs) x
    -> Eff
         (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
         x)
-> Eff
     (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
     x
forall a b. a -> (a -> b) -> b
& (ChainEffect
 ~> Eff
      (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs))
-> Eff (ChainEffect : ChainControlEffect : effs)
   ~> Eff
        (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
forall (f :: * -> *) (g :: * -> *) (h :: * -> *)
       (effs :: [* -> *]).
(f ~> Eff (g : h : effs)) -> Eff (f : effs) ~> Eff (g : h : effs)
reinterpret2 @ChainEffect @(State ChainState) @(LogMsg ChainEvent) (Params
-> ChainEffect
   ~> Eff
        (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
forall (effs :: [* -> *]).
Members ChainEffs effs =>
Params -> ChainEffect ~> Eff effs
handleChain Params
params)
        Eff
  (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
  x
-> (Eff
      (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
      x
    -> Eff (LogMsg ChainEvent : ChainControlEffect : effs) x)
-> Eff (LogMsg ChainEvent : ChainControlEffect : effs) x
forall a b. a -> (a -> b) -> b
& (State ChainState
 ~> Eff (LogMsg ChainEvent : ChainControlEffect : effs))
-> Eff
     (State ChainState : LogMsg ChainEvent : ChainControlEffect : effs)
   ~> Eff (LogMsg ChainEvent : ChainControlEffect : effs)
forall (eff :: * -> *) (effs :: [* -> *]).
(eff ~> Eff effs) -> Eff (eff : effs) ~> Eff effs
interpret (Lens' EmulatorState ChainState
-> State ChainState
   ~> Eff (LogMsg ChainEvent : ChainControlEffect : effs)
forall s2 (effs :: [* -> *]) s1.
Member (State s2) effs =>
Lens' s2 s1 -> State s1 ~> Eff effs
Eff.handleZoomedState Lens' EmulatorState ChainState
chainState)
        Eff (LogMsg ChainEvent : ChainControlEffect : effs) x
-> (Eff (LogMsg ChainEvent : ChainControlEffect : effs) x
    -> Eff (ChainControlEffect : effs) x)
-> Eff (ChainControlEffect : effs) x
forall a b. a -> (a -> b) -> b
& (LogMsg ChainEvent ~> Eff (ChainControlEffect : effs))
-> Eff (LogMsg ChainEvent : ChainControlEffect : effs)
   ~> Eff (ChainControlEffect : effs)
forall (eff :: * -> *) (effs :: [* -> *]).
(eff ~> Eff effs) -> Eff (eff : effs) ~> Eff effs
interpret ((ChainEvent -> EmulatorEvent')
-> LogMsg ChainEvent ~> Eff (ChainControlEffect : effs)
forall a b (effs :: [* -> *]).
Member (LogMsg b) effs =>
(a -> b) -> LogMsg a ~> Eff effs
mapLog (AReview EmulatorEvent' ChainEvent -> ChainEvent -> EmulatorEvent'
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview EmulatorEvent' ChainEvent
Prism' EmulatorEvent' ChainEvent
chainEvent))
        Eff (ChainControlEffect : effs) x
-> (Eff (ChainControlEffect : effs) x
    -> Eff (State ChainState : LogMsg ChainEvent : effs) x)
-> Eff (State ChainState : LogMsg ChainEvent : effs) x
forall a b. a -> (a -> b) -> b
& (ChainControlEffect
 ~> Eff (State ChainState : LogMsg ChainEvent : effs))
-> Eff (ChainControlEffect : effs)
   ~> Eff (State ChainState : LogMsg ChainEvent : effs)
forall (f :: * -> *) (g :: * -> *) (h :: * -> *)
       (effs :: [* -> *]).
(f ~> Eff (g : h : effs)) -> Eff (f : effs) ~> Eff (g : h : effs)
reinterpret2 @ChainControlEffect @(State ChainState) @(LogMsg ChainEvent) (Params
-> ChainControlEffect
   ~> Eff (State ChainState : LogMsg ChainEvent : effs)
forall (effs :: [* -> *]).
Members ChainEffs effs =>
Params -> ChainControlEffect ~> Eff effs
handleControlChain Params
params)
        Eff (State ChainState : LogMsg ChainEvent : effs) x
-> (Eff (State ChainState : LogMsg ChainEvent : effs) x
    -> Eff (LogMsg ChainEvent : effs) x)
-> Eff (LogMsg ChainEvent : effs) x
forall a b. a -> (a -> b) -> b
& (State ChainState ~> Eff (LogMsg ChainEvent : effs))
-> Eff (State ChainState : LogMsg ChainEvent : effs)
   ~> Eff (LogMsg ChainEvent : effs)
forall (eff :: * -> *) (effs :: [* -> *]).
(eff ~> Eff effs) -> Eff (eff : effs) ~> Eff effs
interpret (Lens' EmulatorState ChainState
-> State ChainState ~> Eff (LogMsg ChainEvent : effs)
forall s2 (effs :: [* -> *]) s1.
Member (State s2) effs =>
Lens' s2 s1 -> State s1 ~> Eff effs
Eff.handleZoomedState Lens' EmulatorState ChainState
chainState)
        Eff (LogMsg ChainEvent : effs) x
-> (Eff (LogMsg ChainEvent : effs) x -> Eff effs x) -> Eff effs x
forall a b. a -> (a -> b) -> b
& (LogMsg ChainEvent ~> Eff effs)
-> Eff (LogMsg ChainEvent : effs) ~> Eff effs
forall (eff :: * -> *) (effs :: [* -> *]).
(eff ~> Eff effs) -> Eff (eff : effs) ~> Eff effs
interpret ((ChainEvent -> EmulatorEvent') -> LogMsg ChainEvent ~> Eff effs
forall a b (effs :: [* -> *]).
Member (LogMsg b) effs =>
(a -> b) -> LogMsg a ~> Eff effs
mapLog (AReview EmulatorEvent' ChainEvent -> ChainEvent -> EmulatorEvent'
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview EmulatorEvent' ChainEvent
Prism' EmulatorEvent' ChainEvent
chainEvent))