{-# 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.HashSet as HashSet
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
  | NTSubmissionEdited
  | NTSubmissionUserCreated
  | NTSubmissionUserDeleted
  | NTSheetActive
  | NTSheetHint
  | NTSheetSolution
  | NTSheetSoonInactive
  | NTSheetInactive
  | NTCorrectionsAssigned
  | NTCorrectionsNotDistributed
  | NTUserRightsUpdate
  | NTUserAuthModeUpdate
  | NTExamRegistrationActive
  | NTExamRegistrationSoonInactive
  | NTExamDeregistrationSoonInactive
  | NTExamResult
  | NTAllocationStaffRegister
  | NTAllocationAllocation
  | NTAllocationRegister
  | NTAllocationOutdatedRatings
  | NTAllocationUnratedApplications
  | NTAllocationResults
  | NTExamOfficeExamResults
  | NTExamOfficeExamResultsChanged
  | NTCourseRegistered
  deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)

instance Universe NotificationTrigger
instance Finite NotificationTrigger

instance Hashable NotificationTrigger

nullaryPathPiece ''NotificationTrigger $ camelToPathPiece' 1
pathPieceJSON ''NotificationTrigger
pathPieceJSONKey ''NotificationTrigger


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

instance Default NotificationSettings where
  def = NotificationSettings $ not . flip HashSet.member defaultOff
    where
      defaultOff :: HashSet NotificationTrigger
      defaultOff = HashSet.fromList
        [ NTSheetSoonInactive
        , NTExamRegistrationSoonInactive
        ]

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 -> fromMaybe (notificationAllowed def n) $ HashMap.lookup n o'

derivePersistFieldJSON ''NotificationSettings
