{-# LANGUAGE RecordWildCards  #-}
{-# LANGUAGE TypeApplications #-}

-- | Servant client for PAB
module Plutus.PAB.Webserver.Client (
    PabClient(..)
  , InstanceClient(..)
  , pabClient
) where

import Data.Aeson (FromJSON, ToJSON (..))
import Data.Aeson qualified as JSON
import Data.Proxy
import Data.Text (Text)
import Plutus.PAB.Events.Contract
import Plutus.PAB.Instances ()
import Plutus.PAB.Webserver.API
import Plutus.PAB.Webserver.Types
import Servant.API
import Servant.Client

-- | Client for PAB. The first type-argument is contract type that is used for PAB-simulator.
data PabClient t walletId = PabClient
  { PabClient t walletId -> ClientM ()
healthcheck      :: ClientM ()
      -- ^ call healthcheck method
  , PabClient t walletId -> ClientM (FullReport t)
fullreport       :: ClientM (FullReport t)
      -- ^ call fullreport method
  , PabClient t walletId
-> ContractActivationArgs t -> ClientM ContractInstanceId
activateContract :: ContractActivationArgs t -> ClientM ContractInstanceId
      -- ^ call activate contract method
  , PabClient t walletId -> ContractInstanceId -> InstanceClient t
instanceClient   :: ContractInstanceId -> InstanceClient t
      -- ^ call methods for instance client. We should turn @ContractInstanceId@ to @Text@ for the first argument.
  , PabClient t walletId
-> walletId
-> Maybe Text
-> ClientM [ContractInstanceClientState t]
getWallet        :: walletId -> Maybe Text -> ClientM [ContractInstanceClientState t]
      -- ^ get wallet instances
  , PabClient t walletId
-> Maybe Text -> ClientM [ContractInstanceClientState t]
getInstances     :: Maybe Text -> ClientM [ContractInstanceClientState t]
      -- ^ get instances
  , PabClient t walletId -> ClientM [ContractSignatureResponse t]
getDefinitions   :: ClientM [ContractSignatureResponse t]
      -- ^ get definitions
  }

-- | Contract instance endpoints
data InstanceClient t = InstanceClient
  { InstanceClient t -> ClientM (ContractInstanceClientState t)
getInstanceStatus    :: ClientM (ContractInstanceClientState t)
      -- ^ get instance status
  , InstanceClient t -> ClientM (ContractSignatureResponse t)
getInstanceSchema    :: ClientM (ContractSignatureResponse t)
      -- ^ get instance schema
  , InstanceClient t -> String -> Value -> ClientM ()
callInstanceEndpoint :: String -> JSON.Value -> ClientM ()
      -- ^ call instance endpoint
  , InstanceClient t -> ClientM ()
stopInstance         :: ClientM ()
      -- ^ call stop instance method
  }

-- | Init generic pab client
pabClient :: forall t walletId. (ToJSON t, FromJSON t, ToHttpApiData walletId) => PabClient t walletId
pabClient :: PabClient t walletId
pabClient = PabClient :: forall t walletId.
ClientM ()
-> ClientM (FullReport t)
-> (ContractActivationArgs t -> ClientM ContractInstanceId)
-> (ContractInstanceId -> InstanceClient t)
-> (walletId
    -> Maybe Text -> ClientM [ContractInstanceClientState t])
-> (Maybe Text -> ClientM [ContractInstanceClientState t])
-> ClientM [ContractSignatureResponse t]
-> PabClient t walletId
PabClient{ClientM [ContractSignatureResponse t]
ClientM ()
ClientM (FullReport t)
walletId -> Maybe Text -> ClientM [ContractInstanceClientState t]
Maybe Text -> ClientM [ContractInstanceClientState t]
ContractInstanceId -> InstanceClient t
ContractActivationArgs t -> ClientM ContractInstanceId
instanceClient :: ContractInstanceId -> InstanceClient t
getDefinitions :: ClientM [ContractSignatureResponse t]
getInstances :: Maybe Text -> ClientM [ContractInstanceClientState t]
getWallet :: walletId -> Maybe Text -> ClientM [ContractInstanceClientState t]
activateContract :: ContractActivationArgs t -> ClientM ContractInstanceId
fullreport :: ClientM (FullReport t)
healthcheck :: ClientM ()
getDefinitions :: ClientM [ContractSignatureResponse t]
getInstances :: Maybe Text -> ClientM [ContractInstanceClientState t]
getWallet :: walletId -> Maybe Text -> ClientM [ContractInstanceClientState t]
instanceClient :: ContractInstanceId -> InstanceClient t
activateContract :: ContractActivationArgs t -> ClientM ContractInstanceId
fullreport :: ClientM (FullReport t)
healthcheck :: ClientM ()
..}
  where
    (ClientM ()
healthcheck
      :<|> ClientM (FullReport t)
fullreport
      :<|> ContractActivationArgs t -> ClientM ContractInstanceId
activateContract
      :<|> ContractInstanceId
-> ClientM (ContractInstanceClientState t)
   :<|> (ClientM (ContractSignatureResponse t)
         :<|> ((String -> Value -> ClientM ()) :<|> ClientM ()))
toInstanceClient
      :<|> walletId -> Maybe Text -> ClientM [ContractInstanceClientState t]
getWallet
      :<|> Maybe Text -> ClientM [ContractInstanceClientState t]
getInstances
      :<|> ClientM [ContractSignatureResponse t]
getDefinitions
      ) = Proxy (API t walletId) -> Client ClientM (API t walletId)
forall api.
HasClient ClientM api =>
Proxy api -> Client ClientM api
client (Proxy (API t walletId)
forall k (t :: k). Proxy t
Proxy @(API t walletId))

    instanceClient :: ContractInstanceId -> InstanceClient t
instanceClient ContractInstanceId
cid = InstanceClient :: forall t.
ClientM (ContractInstanceClientState t)
-> ClientM (ContractSignatureResponse t)
-> (String -> Value -> ClientM ())
-> ClientM ()
-> InstanceClient t
InstanceClient{ClientM ()
ClientM (ContractInstanceClientState t)
ClientM (ContractSignatureResponse t)
String -> Value -> ClientM ()
stopInstance :: ClientM ()
callInstanceEndpoint :: String -> Value -> ClientM ()
getInstanceSchema :: ClientM (ContractSignatureResponse t)
getInstanceStatus :: ClientM (ContractInstanceClientState t)
stopInstance :: ClientM ()
callInstanceEndpoint :: String -> Value -> ClientM ()
getInstanceSchema :: ClientM (ContractSignatureResponse t)
getInstanceStatus :: ClientM (ContractInstanceClientState t)
..}
        where
          (ClientM (ContractInstanceClientState t)
getInstanceStatus
            :<|> ClientM (ContractSignatureResponse t)
getInstanceSchema
            :<|> String -> Value -> ClientM ()
callInstanceEndpoint
            :<|> ClientM ()
stopInstance
            ) = ContractInstanceId
-> ClientM (ContractInstanceClientState t)
   :<|> (ClientM (ContractSignatureResponse t)
         :<|> ((String -> Value -> ClientM ()) :<|> ClientM ()))
toInstanceClient ContractInstanceId
cid