module Data.Time.RRule.Types
  ( defaultRRule
  , RRule(..)
  , Day(..)
  , Frequency(..)
  , ToRRule(toRRule)
  )
where

import Prelude hiding (until)
import Data.List.NonEmpty (NonEmpty(..))
import Data.Text (Text, intercalate, pack, unpack)
import Data.Time.Format (formatTime, defaultTimeLocale)
import Data.Time.Clock (UTCTime)

class Show a => ToRRule a where
  toRRule :: a -> Text
  toRRule = pack . show

instance ToRRule Int

instance ToRRule a => ToRRule (NonEmpty a) where
  toRRule (x :| xs) = intercalate "," $ toRRule x : map toRRule xs

instance (Show a, Integral a, ToRRule b) => ToRRule (a, b) where
  toRRule (a, b) = (if a == 0 then "" else pack $ show a) <> toRRule b

instance ToRRule UTCTime where
  toRRule = pack . formatTime defaultTimeLocale "%Y%m%dT%H%M%SZ"

instance ToRRule a => ToRRule (Maybe a) where
  toRRule Nothing = ""
  toRRule (Just a) = toRRule a

data Frequency
  = Secondly
  | Minutely
  | Hourly
  | Daily
  | Weekly
  | Monthly
  | Yearly
  deriving (Eq, Show)

instance ToRRule Frequency where
  toRRule = \case
    Secondly -> "SECONDLY"
    Minutely -> "MINUTELY"
    Hourly   -> "HOURLY"
    Daily    -> "DAILY"
    Weekly   -> "WEEKLY"
    Monthly  -> "MONTHLY"
    Yearly   -> "YEARLY"

data Day = Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday
  deriving (Eq, Show)

instance ToRRule Day where
  toRRule = \case
    Sunday    -> "SU"
    Monday    -> "MO"
    Tuesday   -> "TU"
    Wednesday -> "WE"
    Thursday  -> "TH"
    Friday    -> "FR"
    Saturday  -> "SA"

data RRule = RRule
  { prefix     :: Bool                        -- ^ whether this rule has the "RRULE:" prefix
  , weekStart  :: Maybe Day                   -- ^ starting day of the week
  , frequency  :: Maybe Frequency             -- ^ how often to recur
  , count      :: Maybe Int                   -- ^ how many times to recur
  , until      :: Maybe UTCTime               -- ^ what UTCTime to stop recurring after
  , interval   :: Maybe Int                   -- ^ number of units to wait before recurring
  , bySecond   :: Maybe (NonEmpty Int)        -- ^ which second(s) to recur on
  , byMinute   :: Maybe (NonEmpty Int)        -- ^ which minute(s) to recur on
  , byHour     :: Maybe (NonEmpty Int)        -- ^ which hour(s) to recur on
  , byDay      :: Maybe (NonEmpty (Int, Day)) -- ^ which days(s) to recur on
  , byWeekNo   :: Maybe (NonEmpty Int)        -- ^ which week number(s) to recur on
  , byMonth    :: Maybe (NonEmpty Int)        -- ^ which month(s) to recur on
  , byMonthDay :: Maybe (NonEmpty Int)        -- ^ which day(s) of the month to recur on
  , byYearDay  :: Maybe (NonEmpty Int)        -- ^ which day(s) of the year to recur on
  , bySetPos   :: Maybe (NonEmpty Int)        -- ^ which occurrence of the rule inside the frequency period
  }
  deriving (Eq, Show)

defaultRRule :: RRule
defaultRRule = RRule
  { prefix     = False
  , weekStart  = Nothing
  , frequency  = Nothing
  , count      = Nothing
  , until      = Nothing
  , interval   = Nothing
  , bySecond   = Nothing
  , byMinute   = Nothing
  , byHour     = Nothing
  , byDay      = Nothing
  , byWeekNo   = Nothing
  , byMonth    = Nothing
  , byMonthDay = Nothing
  , byYearDay  = Nothing
  , bySetPos   = Nothing
  }