module Control.Monad.Operational.Now where

import           Control.Monad.Operational
import           Control.Monad.Operational.Interpret
import           Data.IORef                (IORef, newIORef, readIORef,
                                            writeIORef)
import           Data.Time                 (NominalDiffTime, UTCTime,
                                            addUTCTime, getCurrentTime)

data NowI a where
  NowI :: NowI UTCTime

interpretNow :: NowI a -> IO a
interpretNow NowI = getCurrentTime

interpretNowMoving :: UTCTime -> NominalDiffTime -> IO (ApplyInstr IO NowI)
interpretNowMoving start interval = do
  timeRef <- newIORef start
  return (interpretNowMoving' timeRef interval)

interpretNowMoving' :: IORef UTCTime -> NominalDiffTime -> ApplyInstr IO NowI
interpretNowMoving' timeRef interval = ApplyInstr $ \NowI -> do
  time <- readIORef timeRef
  writeIORef timeRef (addUTCTime interval time)
  return time

interpretNowConstant :: Applicative m => UTCTime -> NowI a -> m a
interpretNowConstant time NowI = pure time