{-# options_haddock prune #-}

-- |'Time' interpreters for the data types from "Data.Time", Internal
module Polysemy.Time.Interpreter.Ghc where

import Control.Concurrent (threadDelay)
import Data.Time (Day, NominalDiffTime, UTCTime, utctDay)
import Data.Time.Clock.System (getSystemTime, systemToUTCTime)

import Polysemy.Time.At (interceptTimeAt, interceptTimeConstant, interceptTimeConstantNow)
import Polysemy.Time.Data.TimeUnit (MicroSeconds (MicroSeconds), convert)
import qualified Polysemy.Time.Effect.Time as Time
import Polysemy.Time.Effect.Time (Time)
import Polysemy.Time.Orphans ()

-- |Convenience alias for 'Data.Time'.
type GhcTime =
  Time UTCTime Day

now ::
  Member (Embed IO) r =>
  Sem r UTCTime
now :: forall (r :: EffectRow). Member (Embed IO) r => Sem r UTCTime
now =
  SystemTime -> UTCTime
systemToUTCTime forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed IO SystemTime
getSystemTime

-- |Interpret 'Time' with the types from 'Data.Time'.
interpretTimeGhc ::
  Member (Embed IO) r =>
  InterpreterFor GhcTime r
interpretTimeGhc :: forall (r :: EffectRow).
Member (Embed IO) r =>
InterpreterFor GhcTime r
interpretTimeGhc =
  forall (e :: (* -> *) -> * -> *) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret \case
    GhcTime (Sem rInitial) x
Time.Now ->
      forall (r :: EffectRow). Member (Embed IO) r => Sem r UTCTime
now
    GhcTime (Sem rInitial) x
Time.Today ->
      UTCTime -> Day
utctDay forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (r :: EffectRow). Member (Embed IO) r => Sem r UTCTime
now
    Time.Sleep (forall a b. (TimeUnit a, TimeUnit b) => a -> b
convert -> MicroSeconds Int64
us) ->
      forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Int -> IO ()
threadDelay (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
us))
    Time.SetTime UTCTime
_ ->
      forall (f :: * -> *). Applicative f => f ()
unit
    Time.Adjust u1
_ ->
      forall (f :: * -> *). Applicative f => f ()
unit
    Time.SetDate Day
_ ->
      forall (f :: * -> *). Applicative f => f ()
unit

-- |Interpret 'Time' with the types from 'Data.Time', customizing the current time at the start of interpretation.
interpretTimeGhcAt ::
  Member (Embed IO) r =>
  UTCTime ->
  InterpreterFor GhcTime r
interpretTimeGhcAt :: forall (r :: EffectRow).
Member (Embed IO) r =>
UTCTime -> InterpreterFor GhcTime r
interpretTimeGhcAt UTCTime
t =
  forall (r :: EffectRow).
Member (Embed IO) r =>
InterpreterFor GhcTime r
interpretTimeGhc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall diff t d (r :: EffectRow) a.
(TimeUnit diff, Torsor t diff, HasDate t d,
 Members '[Time t d, Embed IO] r) =>
t -> Sem r a -> Sem r a
interceptTimeAt @NominalDiffTime UTCTime
t

-- |Interpret 'Time' with the types from 'Data.Time', customizing the current time to be constant.
-- Sleeping will only terminate after the time has been advanced by `Time.adjust`.
interpretTimeGhcConstant ::
  Member (Embed IO) r =>
  UTCTime ->
  InterpreterFor GhcTime r
interpretTimeGhcConstant :: forall (r :: EffectRow).
Member (Embed IO) r =>
UTCTime -> InterpreterFor GhcTime r
interpretTimeGhcConstant UTCTime
t =
  forall (r :: EffectRow).
Member (Embed IO) r =>
InterpreterFor GhcTime r
interpretTimeGhc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t d diff (r :: EffectRow) a.
(Ord diff, HasDate t d, TimeUnit diff, Torsor t diff,
 Members '[Time t d, Embed IO] r) =>
t -> Sem r a -> Sem r a
interceptTimeConstant UTCTime
t

-- |Interpret 'Time' with the types from 'Data.Time', customizing the current time to be constantly the time at the
-- start of interpretation.
-- Sleeping will only terminate after the time has been advanced by `Time.adjust`.
interpretTimeGhcConstantNow ::
  Member (Embed IO) r =>
  InterpreterFor GhcTime r
interpretTimeGhcConstantNow :: forall (r :: EffectRow).
Member (Embed IO) r =>
InterpreterFor GhcTime r
interpretTimeGhcConstantNow =
  forall (r :: EffectRow).
Member (Embed IO) r =>
InterpreterFor GhcTime r
interpretTimeGhc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t d diff (r :: EffectRow) a.
(Ord diff, HasDate t d, TimeUnit diff, Torsor t diff,
 Members '[Time t d, Embed IO] r) =>
Sem r a -> Sem r a
interceptTimeConstantNow @UTCTime