module Handler.Utils.ExamOffice.Course
  ( courseExamOfficeSchools
  ) where

import Import.NoFoundation

import qualified Database.Esqueleto as E
import qualified Database.Esqueleto.Utils as E


courseExamOfficeSchools :: E.SqlExpr (E.Value UserId)
                        -> E.SqlExpr (E.Value CourseId)
                        -> E.SqlQuery (E.SqlExpr (Entity School), E.SqlExpr (E.Value Bool)) -- ^ @Entity School@ and @forced@
courseExamOfficeSchools user course = E.from $ \((school `E.InnerJoin` userFunction) `E.LeftOuterJoin` (examOfficeField `E.FullOuterJoin` examOfficeUser))
  -> E.distinctOnOrderBy [E.asc $ school E.^. SchoolId] $ do
       E.on   E.false
       E.on $ (      examOfficeUser E.?. ExamOfficeUserUser E.==. E.just user
               E.&&. examOfficeUser E.?. ExamOfficeUserOffice E.==. E.just (userFunction E.^. UserFunctionUser)
              )
        E.||. (      examOfficeField E.?. ExamOfficeFieldOffice E.==. E.just (userFunction E.^. UserFunctionUser)
               E.&&. E.exists ( E.from $ \studyFeatures ->
                                  E.where_ $ E.just (studyFeatures E.^. StudyFeaturesField) E.==. examOfficeField E.?. ExamOfficeFieldField
                                       E.&&. studyFeatures E.^. StudyFeaturesUser E.==. user
                              )
              )
       E.on $ school E.^. SchoolId E.==. userFunction E.^. UserFunctionSchool
        E.&&. userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice

       let byUser = E.not_ . E.isNothing $ examOfficeUser E.?. ExamOfficeUserId
           byField = E.not_ . E.isNothing $ examOfficeField E.?. ExamOfficeFieldId
           byCourse = E.exists . E.from $ \course' ->
             E.where_ $ course' E.^. CourseId E.==. course
                  E.&&. course' E.^. CourseSchool E.==. school E.^. SchoolId

           forced = byUser
              E.||. byCourse
              E.||. E.maybe E.true id (examOfficeField E.?. ExamOfficeFieldForced)

       E.where_ $ byUser E.||. byField E.||. byCourse

       E.orderBy [E.desc forced]
       return (school, forced)
