-- | A /job/ makes requests, performs actions, and returns

module SupplyChain.Job
  (
    {- * Type -} Job,
    {- * Construction -} perform, order, effect,
    {- * Running -} run, eval,
    {- * Alteration -} alter, alter',
  )
  where

import SupplyChain.Core.Effect (Effect)
import SupplyChain.Core.Job (Job)

import qualified SupplyChain.Core.Job as Job

import Control.Monad (Monad)
import Data.Function ((.))
import Data.Functor.Const (Const)
import Data.Void (Void)

alter :: (forall x. Effect up action x -> Job up' action' x)
    -- ^ Transformation applied to each effect that the job evokes
    -> Job up action product -> Job up' action' product
alter :: forall (up :: * -> *) (action :: * -> *) (up' :: * -> *)
       (action' :: * -> *) product.
(forall x. Effect up action x -> Job up' action' x)
-> Job up action product -> Job up' action' product
alter forall x. Effect up action x -> Job up' action' x
f = forall (up :: * -> *) (action :: * -> *) (up' :: * -> *)
       (action' :: * -> *) product.
(forall x. Effect up action x -> Job up' action' x)
-> Job up action product -> Job up' action' product
Job.alter forall x. Effect up action x -> Job up' action' x
f

alter' :: (forall x. Effect up action x -> Effect up' action' x)
    -- ^ Transformation applied to each effect that the job evokes
    -> Job up action product -> Job up' action' product
alter' :: forall (up :: * -> *) (action :: * -> *) (up' :: * -> *)
       (action' :: * -> *) product.
(forall x. Effect up action x -> Effect up' action' x)
-> Job up action product -> Job up' action' product
alter' forall x. Effect up action x -> Effect up' action' x
f = forall (up :: * -> *) (action :: * -> *) (up' :: * -> *)
       (action' :: * -> *) product.
(forall x. Effect up action x -> Job up' action' x)
-> Job up action product -> Job up' action' product
Job.alter (forall (up :: * -> *) (action :: * -> *) product.
Effect up action product -> Job up action product
effect forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall x. Effect up action x -> Effect up' action' x
f)

perform :: action product -- ^ Action
    -> Job up action product -- ^ Job
perform :: forall (action :: * -> *) product (up :: * -> *).
action product -> Job up action product
perform = forall (action :: * -> *) product (up :: * -> *).
action product -> Job up action product
Job.perform

order :: up product -- ^ Request
    -> Job up action product -- ^ Job
order :: forall (up :: * -> *) product (action :: * -> *).
up product -> Job up action product
order = forall (up :: * -> *) product (action :: * -> *).
up product -> Job up action product
Job.order

effect :: Effect up action product -- ^ Effect
    -> Job up action product -- ^ Job
effect :: forall (up :: * -> *) (action :: * -> *) product.
Effect up action product -> Job up action product
effect = forall (up :: * -> *) (action :: * -> *) product.
Effect up action product -> Job up action product
Job.effect

{-| Run a job in its action context

   The job must not make requests, so its upstream interface
   is @Const Void@. -}
run :: Monad action =>
    Job (Const Void) action product -- ^ Job
    -> action product -- ^ Action
run :: forall (action :: * -> *) product.
Monad action =>
Job (Const Void) action product -> action product
run = forall (action :: * -> *) product.
Monad action =>
Job (Const Void) action product -> action product
Job.run

{-| Evaluate a job with no context

    The job must evokes neither request nor actions, so both
    its upstream and action contexts are @Const Void@. -}
eval :: Job (Const Void) (Const Void) product -- ^ Job
    -> product -- ^ Result
eval :: forall product. Job (Const Void) (Const Void) product -> product
eval = forall product. Job (Const Void) (Const Void) product -> product
Job.eval