module Handler.Utils.ExamOffice.ExternalExam
  ( resultIsSynced
  , examOfficeExternalExamResultAuth
  ) where

import Import.NoFoundation
import Handler.Utils.StudyFeatures

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


resultIsSynced :: E.SqlExpr (E.Value UserId) -- ^ office
               -> E.SqlExpr (Entity ExternalExamResult)
               -> E.SqlExpr (E.Value Bool)
resultIsSynced authId eexamResult = (hasSchool E.&&. allSchools) E.||. (E.not_ hasSchool E.&&. anySync)
  where
    anySync = E.exists . E.from $ \synced ->
      E.where_ $ synced E.^. ExamOfficeExternalResultSyncedResult E.==. eexamResult E.^. ExternalExamResultId
           E.&&. synced E.^. ExamOfficeExternalResultSyncedTime   E.>=. eexamResult E.^. ExternalExamResultLastChanged

    hasSchool = E.exists . E.from $ \userFunction ->
      E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
           E.&&. userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
    allSchools = E.not_ . E.exists . E.from $ \userFunction -> do
      E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
           E.&&. userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
      E.where_ . E.not_ . E.exists . E.from $ \synced ->
        E.where_ $ synced E.^. ExamOfficeExternalResultSyncedSchool E.==. E.just (userFunction E.^. UserFunctionSchool)
             E.&&. synced E.^. ExamOfficeExternalResultSyncedResult E.==. eexamResult E.^. ExternalExamResultId
             E.&&. synced E.^. ExamOfficeExternalResultSyncedTime   E.>=. eexamResult E.^. ExternalExamResultLastChanged


examOfficeExternalExamResultAuth :: E.SqlExpr (E.Value UserId) -- ^ office
                                 -> E.SqlExpr (Entity ExternalExamResult)
                                 -> E.SqlExpr (E.Value Bool)
examOfficeExternalExamResultAuth authId eexamResult = ((isOffice E.||. isSystemOffice) E.&&. authByUser) E.||. authByField E.||. authBySchool E.||. authByExtraSchool
  where
    authByField = E.exists . E.from $ \(examOfficeField `E.InnerJoin` studyFeatures) -> do
      E.on $ studyFeatures E.^. StudyFeaturesField E.==. examOfficeField E.^. ExamOfficeFieldField
      E.where_ . E.maybe E.false id . E.subSelectMaybe . E.from $ \externalExam -> do
        E.where_ $ externalExam E.^. ExternalExamId E.==. eexamResult E.^. ExternalExamResultExam
        return . E.just $ isExternalExamStudyFeature externalExam studyFeatures
      E.where_ $ studyFeatures E.^. StudyFeaturesUser E.==. eexamResult E.^. ExternalExamResultUser
           E.&&. examOfficeField E.^. ExamOfficeFieldOffice E.==. authId
           E.&&. examOfficeField E.^. ExamOfficeFieldField E.==. studyFeatures E.^. StudyFeaturesField
      E.where_ $ examOfficeField E.^. ExamOfficeFieldForced
           E.||. E.exists (E.from $ \userFunction ->
                             E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
                                  E.&&. userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
                          )

    authByUser = E.exists . E.from $ \examOfficeUser ->
      E.where_ $ examOfficeUser E.^. ExamOfficeUserOffice E.==. authId
           E.&&. examOfficeUser E.^. ExamOfficeUserUser E.==. eexamResult E.^. ExternalExamResultUser

    isOffice = E.exists . E.from $ \userFunction ->
      E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
           E.&&. userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
    isSystemOffice = E.exists . E.from $ \userSystemFunction -> 
      E.where_ $ userSystemFunction E.^. UserSystemFunctionUser E.==. authId
           E.&&. userSystemFunction E.^. UserSystemFunctionFunction E.==. E.val SystemExamOffice
           E.&&. E.not_ (userSystemFunction E.^. UserSystemFunctionIsOptOut)

    authBySchool = E.exists . E.from $ \(userFunction `E.InnerJoin` eexam) -> do
      E.on $ userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
       E.&&. userFunction E.^. UserFunctionSchool E.==. eexam E.^. ExternalExamSchool
      E.where_ $ eexam E.^. ExternalExamId E.==. eexamResult E.^. ExternalExamResultExam
      E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
    authByExtraSchool = E.exists . E.from $ \(userFunction `E.InnerJoin` eexamSchool) -> do
      E.on $ userFunction E.^. UserFunctionFunction E.==. E.val SchoolExamOffice
       E.&&. userFunction E.^. UserFunctionSchool E.==. eexamSchool E.^. ExternalExamOfficeSchoolSchool
      E.where_ $ eexamSchool E.^. ExternalExamOfficeSchoolExam E.==. eexamResult E.^. ExternalExamResultExam
      E.where_ $ userFunction E.^. UserFunctionUser E.==. authId
