-- | Description: a /vendor/ responds to requests, makes requests, and
--                performs actions

module SupplyChain.Core.Vendor
  (
    {- * Type -} Vendor (..),
    {- * Running -} run, eval,
    {- * Alteration -} alter,
  )
  where

import Control.Monad (Monad)
import Data.Functor.Const (Const)
import Data.Void (Void)
import SupplyChain.Core.Effect (Effect)
import SupplyChain.Core.Job (Job)
import SupplyChain.Core.VendorAndReferral (Vendor (..), Referral (..))

import qualified SupplyChain.Core.Job as Job
import qualified SupplyChain.Core.VendorAndReferral as VendorAndReferral

{-| An action in which a vendor handles a single request

    The action returns a 'Referral', which contains two things:

    - The response to the request
    - A new version of the vendor
-}
run :: Monad action => Vendor (Const Void) down action
    -> down product -- ^ Request
    -> action (Referral (Const Void) down action product)
run :: forall (action :: * -> *) (down :: * -> *) product.
Monad action =>
Vendor (Const Void) down action
-> down product
-> action (Referral (Const Void) down action product)
run Vendor (Const Void) down action
v down product
r = forall (action :: * -> *) product.
Monad action =>
Job (Const Void) action product -> action product
Job.run (forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
Vendor up down action
-> forall product.
   down product -> Job up action (Referral up down action product)
handle Vendor (Const Void) down action
v down product
r)

eval :: Vendor (Const Void) down (Const Void)
    -> down product  -- ^ Request
    -> Referral (Const Void) down (Const Void) product
eval :: forall (down :: * -> *) product.
Vendor (Const Void) down (Const Void)
-> down product -> Referral (Const Void) down (Const Void) product
eval Vendor (Const Void) down (Const Void)
v down product
r = forall product. Job (Const Void) (Const Void) product -> product
Job.eval (forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
Vendor up down action
-> forall product.
   down product -> Job up action (Referral up down action product)
handle Vendor (Const Void) down (Const Void)
v down product
r)

alter :: (forall x. Effect up action x -> Job up' action' x)
    -> Vendor up down action -> Vendor up' down action'
alter :: forall (up :: * -> *) (action :: * -> *) (up' :: * -> *)
       (action' :: * -> *) (down :: * -> *).
(forall x. Effect up action x -> Job up' action' x)
-> Vendor up down action -> Vendor up' down action'
alter = forall (up :: * -> *) (action :: * -> *) (up' :: * -> *)
       (action' :: * -> *) (down :: * -> *).
(forall x. Effect up action x -> Job up' action' x)
-> Vendor up down action -> Vendor up' down action'
VendorAndReferral.alterVendor