module Cron.Types
  ( Cron(..), Crontab
  , CronMatch(..)
  , cronMatchOne
  , CronAbsolute(..)
  , cronCalendarAny
  , CronRepeat(..)
  ) where

import ClassyPrelude

import Utils.Lens.TH

import Data.Time

import Numeric.Natural

import qualified Data.Set as Set


data CronMatch
  = CronMatchAny
  | CronMatchNone
  | CronMatchSome (NonNull (Set Natural))
  | CronMatchStep Natural
  | CronMatchContiguous Natural Natural
  | CronMatchIntersect CronMatch CronMatch
  | CronMatchUnion CronMatch CronMatch
  deriving (Eq, Show, Read)

cronMatchOne :: Natural -> CronMatch
cronMatchOne = CronMatchSome . impureNonNull . Set.singleton

data CronAbsolute
  = CronAsap
  | CronTimestamp
    { cronTimestamp :: LocalTime
    }
  | CronCalendar
    { cronYear, cronWeekYear, cronWeekOfYear, cronDayOfYear
    , cronMonth, cronWeekOfMonth, cronDayOfMonth
    , cronDayOfWeek
    , cronHour, cronMinute, cronSecond :: CronMatch
    }
  | CronNotScheduled
  deriving (Eq, Show, Read)

makeLenses_ ''CronAbsolute

cronCalendarAny :: CronAbsolute
cronCalendarAny = CronCalendar
  { cronYear        = CronMatchAny
  , cronWeekYear    = CronMatchAny
  , cronWeekOfYear  = CronMatchAny
  , cronDayOfYear   = CronMatchAny
  , cronMonth       = CronMatchAny
  , cronWeekOfMonth = CronMatchAny
  , cronDayOfMonth  = CronMatchAny
  , cronDayOfWeek   = CronMatchAny
  , cronHour        = CronMatchAny
  , cronMinute      = CronMatchAny
  , cronSecond      = CronMatchAny
  }

data CronRepeat
  = CronRepeatOnChange
  | CronRepeatScheduled CronAbsolute
  | CronRepeatNever
  deriving (Eq, Show, Read)

data Cron = Cron
  { cronInitial :: CronAbsolute
  , cronRepeat :: CronRepeat
  , cronRateLimit :: NominalDiffTime
  , cronNotAfter :: Either NominalDiffTime CronAbsolute
  }
  deriving (Eq, Show)

makeLenses_ ''Cron

type Crontab a = HashMap a Cron
