{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Hercules.API.State where

import Data.ByteString (ByteString)
import Data.OpenApi qualified as O3
import Data.Swagger (NamedSchema (NamedSchema), binarySchema)
import Data.Swagger.Schema (ToSchema (..))
import Hercules.API.Accounts.Account (Account)
import Hercules.API.Forge.Forge (Forge)
import Hercules.API.Prelude
import Hercules.API.Projects.Project (Project)
import Hercules.API.State.ProjectState (ProjectState)
import Hercules.API.State.StateLockAcquireRequest (StateLockAcquireRequest)
import Hercules.API.State.StateLockAcquireResponse (StateLockAcquireResponse, StateLockAcquiredResponse)
import Hercules.API.State.StateLockUpdateRequest (StateLockUpdateRequest)
import Servant.API

-- | A newtype wrapper for servant-swagger
newtype RawBytes = RawBytes {RawBytes -> ByteString
fromRawBytes :: ByteString}
  deriving newtype (MimeUnrender OctetStream, MimeRender OctetStream)

instance ToSchema RawBytes where
  declareNamedSchema :: Proxy RawBytes -> Declare (Definitions Schema) NamedSchema
declareNamedSchema Proxy RawBytes
_ = NamedSchema -> Declare (Definitions Schema) NamedSchema
forall a. a -> DeclareT (Definitions Schema) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (NamedSchema -> Declare (Definitions Schema) NamedSchema)
-> NamedSchema -> Declare (Definitions Schema) NamedSchema
forall a b. (a -> b) -> a -> b
$ Maybe Text -> Schema -> NamedSchema
NamedSchema (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"RawBytes") Schema
binarySchema

instance O3.ToSchema RawBytes where
  declareNamedSchema :: Proxy RawBytes -> Declare (Definitions Schema) NamedSchema
declareNamedSchema Proxy RawBytes
_ = NamedSchema -> Declare (Definitions Schema) NamedSchema
forall a. a -> DeclareT (Definitions Schema) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (NamedSchema -> Declare (Definitions Schema) NamedSchema)
-> NamedSchema -> Declare (Definitions Schema) NamedSchema
forall a b. (a -> b) -> a -> b
$ Maybe Text -> Schema -> NamedSchema
O3.NamedSchema (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"RawBytes") Schema
O3.binarySchema

type ContentLength = Header "Content-Length" Integer

type ContentDisposition = Header "Content-Disposition" Text

data ProjectStateResourceGroup auth f = ProjectStateResourceGroup
  { forall auth f.
ProjectStateResourceGroup auth f
-> f
   :- (Summary "Upload a state file"
       :> ("state"
           :> (Capture' '[Required, Strict] "stateName" Text
               :> ("data"
                   :> (StreamBody NoFraming OctetStream (SourceIO RawBytes)
                       :> (auth :> Put '[JSON] NoContent))))))
putStateData ::
      f
        :- Summary "Upload a state file"
          :> "state"
          :> Capture' '[Required, Strict] "stateName" Text
          :> "data"
          :> StreamBody NoFraming OctetStream (SourceIO RawBytes)
          :> auth
          :> Put '[JSON] NoContent,
    forall auth f.
ProjectStateResourceGroup auth f
-> f
   :- (Summary "List all state files"
       :> ("states" :> (auth :> Get '[JSON] ProjectState)))
getStates ::
      f
        :- Summary "List all state files"
          :> "states"
          :> auth
          :> Get '[JSON] ProjectState,
    forall auth f.
ProjectStateResourceGroup auth f
-> f
   :- (Summary "Download a state file"
       :> ("state"
           :> (Capture' '[Required, Strict] "stateName" Text
               :> ("data"
                   :> (QueryParam' '[Optional, Strict] "version" Int
                       :> (auth
                           :> StreamGet
                                NoFraming
                                OctetStream
                                (Headers
                                   '[ContentLength, ContentDisposition] (SourceIO RawBytes))))))))
getStateData ::
      f
        :- Summary "Download a state file"
          :> "state"
          :> Capture' '[Required, Strict] "stateName" Text
          :> "data"
          :> QueryParam' '[Optional, Strict] "version" Int
          :> auth
          :> StreamGet NoFraming OctetStream (Headers '[ContentLength, ContentDisposition] (SourceIO RawBytes)),
    forall auth f.
ProjectStateResourceGroup auth f
-> f
   :- (Summary "Acquire a lock"
       :> ("lock"
           :> (Capture' '[Required, Strict] "lockName" Text
               :> (ReqBody '[JSON] StateLockAcquireRequest
                   :> (auth :> Post '[JSON] StateLockAcquireResponse)))))
acquireLock ::
      f
        :- Summary "Acquire a lock"
          :> "lock"
          :> Capture' '[Required, Strict] "lockName" Text
          :> ReqBody '[JSON] StateLockAcquireRequest
          :> auth
          :> Post '[JSON] StateLockAcquireResponse
  }
  deriving ((forall x.
 ProjectStateResourceGroup auth f
 -> Rep (ProjectStateResourceGroup auth f) x)
-> (forall x.
    Rep (ProjectStateResourceGroup auth f) x
    -> ProjectStateResourceGroup auth f)
-> Generic (ProjectStateResourceGroup auth f)
forall x.
Rep (ProjectStateResourceGroup auth f) x
-> ProjectStateResourceGroup auth f
forall x.
ProjectStateResourceGroup auth f
-> Rep (ProjectStateResourceGroup auth f) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall auth f x.
Rep (ProjectStateResourceGroup auth f) x
-> ProjectStateResourceGroup auth f
forall auth f x.
ProjectStateResourceGroup auth f
-> Rep (ProjectStateResourceGroup auth f) x
$cfrom :: forall auth f x.
ProjectStateResourceGroup auth f
-> Rep (ProjectStateResourceGroup auth f) x
from :: forall x.
ProjectStateResourceGroup auth f
-> Rep (ProjectStateResourceGroup auth f) x
$cto :: forall auth f x.
Rep (ProjectStateResourceGroup auth f) x
-> ProjectStateResourceGroup auth f
to :: forall x.
Rep (ProjectStateResourceGroup auth f) x
-> ProjectStateResourceGroup auth f
Generic)

data StateAPI auth f = StateAPI
  { forall auth f.
StateAPI auth f
-> f
   :- Substitute
        ("projects"
         :> (Capture' '[Required, Strict] "projectId" (Id Project)
             :> Placeholder))
        (ToServantApi (ProjectStateResourceGroup auth))
byProjectId ::
      f
        :- Substitute
             ( "projects"
                 :> Capture' '[Required, Strict] "projectId" (Id Project)
                 :> Placeholder
             )
             (ToServantApi (ProjectStateResourceGroup auth)),
    forall auth f.
StateAPI auth f
-> f
   :- Substitute
        ("site"
         :> (Capture' '[Required, Strict] "site" (Name Forge)
             :> ("account"
                 :> (Capture' '[Required, Strict] "account" (Name Account)
                     :> ("project"
                         :> (Capture' '[Required, Strict] "project" (Name Project)
                             :> Placeholder))))))
        (ToServantApi (ProjectStateResourceGroup auth))
byProjectName ::
      f
        :- Substitute
             ( "site"
                 :> Capture' '[Required, Strict] "site" (Name Forge)
                 :> "account"
                 :> Capture' '[Required, Strict] "account" (Name Account)
                 :> "project"
                 :> Capture' '[Required, Strict] "project" (Name Project)
                 :> Placeholder
             )
             (ToServantApi (ProjectStateResourceGroup auth)),
    forall auth f.
StateAPI auth f
-> f
   :- ("lock-leases"
       :> (Capture'
             '[Required, Strict] "lockLeaseId" (Id "StateLockLease")
           :> (ReqBody '[JSON] StateLockUpdateRequest
               :> (auth :> Post '[JSON] StateLockAcquiredResponse))))
updateLockLease ::
      f
        :- "lock-leases"
          :> Capture' '[Required, Strict] "lockLeaseId" (Id "StateLockLease")
          :> ReqBody '[JSON] StateLockUpdateRequest
          :> auth
          :> Post '[JSON] StateLockAcquiredResponse,
    forall auth f.
StateAPI auth f
-> f
   :- ("lock-leases"
       :> (Capture'
             '[Required, Strict] "lockLeaseId" (Id "StateLockLease")
           :> (auth :> Delete '[JSON] NoContent)))
deleteLockLease ::
      f
        :- "lock-leases"
          :> Capture' '[Required, Strict] "lockLeaseId" (Id "StateLockLease")
          :> auth
          :> Delete '[JSON] NoContent
  }
  deriving ((forall x. StateAPI auth f -> Rep (StateAPI auth f) x)
-> (forall x. Rep (StateAPI auth f) x -> StateAPI auth f)
-> Generic (StateAPI auth f)
forall x. Rep (StateAPI auth f) x -> StateAPI auth f
forall x. StateAPI auth f -> Rep (StateAPI auth f) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall auth f x. Rep (StateAPI auth f) x -> StateAPI auth f
forall auth f x. StateAPI auth f -> Rep (StateAPI auth f) x
$cfrom :: forall auth f x. StateAPI auth f -> Rep (StateAPI auth f) x
from :: forall x. StateAPI auth f -> Rep (StateAPI auth f) x
$cto :: forall auth f x. Rep (StateAPI auth f) x -> StateAPI auth f
to :: forall x. Rep (StateAPI auth f) x -> StateAPI auth f
Generic)