{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE UndecidableInstances #-}

{-|
Module: Model.Types.Mail
Description: Types related to Notifications
-}

module Model.Types.Mail
  ( module Model.Types.Mail
  ) where

import Import.NoModel

import qualified Data.Aeson.Types as Aeson

import qualified Data.HashMap.Strict as HashMap


-- ^ `NotificationSettings` is for now a series of boolean checkboxes, i.e. a mapping @NotificationTrigger -> Bool@
--
-- Could maybe be replaced with `Structure Notification` in the long term
data NotificationTrigger
  = NTSubmissionRatedGraded
  | NTSubmissionRated
  | NTSheetActive
  | NTSheetSoonInactive
  | NTSheetInactive
  | NTCorrectionsAssigned
  | NTCorrectionsNotDistributed
  | NTUserRightsUpdate
  deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)

instance Universe NotificationTrigger
instance Finite NotificationTrigger

instance Hashable NotificationTrigger

deriveJSON defaultOptions
  { constructorTagModifier = intercalate "-" . map toLower . drop 1 . splitCamel
  } ''NotificationTrigger

instance ToJSONKey NotificationTrigger where
  toJSONKey = toJSONKeyText $ \v -> let Aeson.String t = toJSON v in t

instance FromJSONKey NotificationTrigger where
  fromJSONKey = FromJSONKeyTextParser $ parseJSON . Aeson.String


newtype NotificationSettings = NotificationSettings { notificationAllowed :: NotificationTrigger -> Bool }
  deriving (Generic, Typeable)
  deriving newtype (Eq, Ord, Read, Show)

instance Default NotificationSettings where
  def = NotificationSettings $ \case
    NTSubmissionRatedGraded -> True
    NTSubmissionRated -> False
    NTSheetActive -> True
    NTSheetSoonInactive -> False
    NTSheetInactive -> True
    NTCorrectionsAssigned -> True
    NTCorrectionsNotDistributed -> True
    NTUserRightsUpdate -> True

instance ToJSON NotificationSettings where
  toJSON v = toJSON . HashMap.fromList $ map (id &&& notificationAllowed v) universeF

instance FromJSON NotificationSettings where
  parseJSON = Aeson.withObject "NotificationSettings" $ \o -> do
    o' <- parseJSON $ Aeson.Object o :: Aeson.Parser (HashMap NotificationTrigger Bool)
    return . NotificationSettings $ \n -> case HashMap.lookup n o' of
      Nothing -> notificationAllowed def n
      Just b  -> b

derivePersistFieldJSON ''NotificationSettings
