{-# LANGUAGE DataKinds          #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE TypeFamilies       #-}
{-# LANGUAGE TypeOperators      #-}

module Plutus.PAB.Webserver.API
    ( API
    , WSAPI
    , SwaggerAPI
    ) where

import Data.Aeson qualified as JSON
import Data.Text (Text)
import Plutus.PAB.Webserver.Types (ContractActivationArgs, ContractInstanceClientState, ContractSignatureResponse,
                                   FullReport)
import Servant.API (Capture, Description, Get, JSON, Post, Put, QueryParam, ReqBody, (:<|>), (:>))
import Servant.API.WebSocket (WebSocketPending)
import Servant.Swagger.UI (SwaggerSchemaUI)
import Wallet.Types (ContractInstanceId)

type WSAPI =
    "ws" :>
        (Capture "contract-instance-id" ContractInstanceId :> WebSocketPending -- Websocket for a specific contract instance
        :<|> WebSocketPending -- Combined websocket (subscription protocol)
        )

-- | PAB client API for contracts of type @t@. An example of @t@ are
--   * "Builtin" contracts that run in the same process as the PAB (ie. the PAB is compiled & distributed with these contracts)
type API t walletId -- see note [WalletID type in wallet API]
    = "api" :> ("healthcheck" :> Description "Is the server alive?" :> Get '[JSON] ()
    :<|> ("fullreport" :> Description "Details of the contracts: the signatures and their states." :> Get '[JSON] (FullReport t))
    :<|> "contract" :> ("activate" :> ReqBody '[JSON] (ContractActivationArgs t) :> Description "Start a new instance." :> Post '[JSON] ContractInstanceId
            :<|> "instance" :>
                    (Capture "contract-instance-id" ContractInstanceId :>
                        (    "status"   :> Description "Current status of contract instance." :> Get '[JSON] (ContractInstanceClientState t)
                        :<|> "schema"   :> Description "Endpoints' schema of contract instance." :> Get '[JSON] (ContractSignatureResponse t)
                        :<|> "endpoint" :> Capture "endpoint-name" String :> ReqBody '[JSON] JSON.Value :> Description "Call an endpoint." :> Post '[JSON] ()
                        :<|> "stop"     :> Description "Terminate the instance." :> Put '[JSON] ()
                        )
                    )
            :<|> "instances" :> "wallet" :> Capture "wallet-id" walletId :> QueryParam "status" Text :> Description "List of contract instances for the wallet filtered by status (active, stopped, done). All by default." :>  Get '[JSON] [ContractInstanceClientState t]
            :<|> "instances" :> QueryParam "status" Text :> Description "List of contract instances filtered by status (active, stopped, done). All by default." :> Get '[JSON] [ContractInstanceClientState t]
            :<|> "definitions" :> Description "list of available contracts." :> Get '[JSON] [ContractSignatureResponse t]
        )
      )

type SwaggerAPI = "swagger" :> SwaggerSchemaUI "swagger-ui" "swagger.json"