module Utils.Sheet where

import Import.NoFoundation
import qualified Database.Esqueleto as E

import Database.Esqueleto.Internal.Language (From) -- cannot be avoided here

-- DB Queries for Sheets that are used in several places

sheetCurrent :: MonadIO m => TermId -> SchoolId -> CourseShorthand -> SqlReadT m (Maybe SheetName)
sheetCurrent tid ssh csh = do
  now <- liftIO getCurrentTime
  sheets <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
    E.on $ sheet      E.^. SheetCourse     E.==. course E.^. CourseId
    E.where_ $ sheet E.^. SheetActiveTo   E.>.  E.val now
        E.&&.  sheet E.^. SheetActiveFrom E.<=. E.val now
        E.&&. course E.^. CourseTerm      E.==. E.val tid
        E.&&. course E.^. CourseSchool    E.==. E.val ssh
        E.&&. course E.^. CourseShorthand E.==. E.val csh
    E.orderBy [E.asc $ sheet E.^. SheetActiveTo]
    E.limit 1
    return $ sheet E.^. SheetName
  return $ case sheets of
    [] -> Nothing
    [E.Value shn] -> Just shn
    _ -> error "SQL Query with limit 1 returned more than one result"


sheetOldUnassigned :: MonadIO m => TermId -> SchoolId -> CourseShorthand -> SqlReadT m (Maybe SheetName)
sheetOldUnassigned tid ssh csh = do
  now <- liftIO getCurrentTime
  sheets <- E.select . E.from $ \(course `E.InnerJoin` sheet) -> do
    E.on $ sheet     E.^. SheetCourse     E.==. course E.^. CourseId
    E.where_ $ sheet E.^. SheetActiveTo   E.<=. E.val now
        E.&&. course E.^. CourseTerm      E.==. E.val tid
        E.&&. course E.^. CourseSchool    E.==. E.val ssh
        E.&&. course E.^. CourseShorthand E.==. E.val csh
    E.where_ . E.exists . E.from $ \submission ->
        E.where_ $ submission E.^. SubmissionSheet E.==. sheet E.^. SheetId
          E.&&.  E.isNothing (submission E.^. SubmissionRatingBy)
    E.orderBy [E.asc $ sheet E.^. SheetActiveTo]
    E.limit 1
    return $ sheet E.^. SheetName
  return $ case sheets of
    [] -> Nothing
    [E.Value shn] -> Just shn
    _ -> error "SQL Query with limit 1 returned more than one result"

-- | Return a specfic file from  a `Sheet`
sheetFileQuery :: MonadResource m => TermId -> SchoolId -> CourseShorthand -> SheetName -> SheetFileType -> FilePath -> Source (SqlPersistT m) (Entity File)
sheetFileQuery tid ssh csh shn sft title = E.selectSource $ E.from $
  \(course `E.InnerJoin` sheet `E.InnerJoin` sFile `E.InnerJoin` file) -> do
  -- Restrict to consistent rows that correspond to each other
  E.on (file  E.^. FileId         E.==. sFile  E.^. SheetFileFile)
  E.on (sFile E.^. SheetFileSheet E.==. sheet  E.^. SheetId)
  E.on (sheet E.^. SheetCourse    E.==. course E.^. CourseId)
  -- filter to requested file
  E.where_ ((file   E.^. FileTitle       E.==. E.val title)
    E.&&.   (sFile  E.^. SheetFileType   E.==. E.val sft  )
    E.&&.   (sheet  E.^. SheetName       E.==. E.val shn  )
    E.&&.   (course E.^. CourseShorthand E.==. E.val csh  )
    E.&&.   (course E.^. CourseSchool    E.==. E.val ssh  )
    E.&&.   (course E.^. CourseTerm      E.==. E.val tid  )
    )
  -- return file entity
  return file

-- | Return all files of a certain `SheetFileType` for a `Sheet`
sheetFilesAllQuery :: MonadResource m => TermId -> SchoolId -> CourseShorthand -> SheetName -> SheetFileType -> Source (SqlPersistT m) (Entity File)
sheetFilesAllQuery tid ssh csh shn sft = E.selectSource $ E.from $
  \(course `E.InnerJoin` sheet `E.InnerJoin` sFile `E.InnerJoin` file) -> do
  -- Restrict to consistent rows that correspond to each other
  E.on (file  E.^. FileId         E.==. sFile  E.^. SheetFileFile)
  E.on (sFile E.^. SheetFileSheet E.==. sheet  E.^. SheetId)
  E.on (sheet E.^. SheetCourse    E.==. course E.^. CourseId)
  -- filter to requested file
  E.where_ ((sheet  E.^. SheetName       E.==. E.val shn  )
    E.&&.   (course E.^. CourseShorthand E.==. E.val csh  )
    E.&&.   (course E.^. CourseSchool    E.==. E.val ssh  )
    E.&&.   (course E.^. CourseTerm      E.==. E.val tid  )
    E.&&.   (sFile  E.^. SheetFileType   E.==. E.val sft  )
    )
  -- return file entity
  return file

-- | Return all files of certain `SheetFileTypes` for a `Sheet`
sheetFilesSFTsQuery :: MonadResource m => TermId -> SchoolId -> CourseShorthand -> SheetName -> [SheetFileType] -> Source (SqlPersistT m) (Entity File)
sheetFilesSFTsQuery tid ssh csh shn sfts = E.selectSource $ E.from $
  \(course `E.InnerJoin` sheet `E.InnerJoin` sFile `E.InnerJoin` file) -> do
  -- Restrict to consistent rows that correspond to each other
  E.on (file  E.^. FileId         E.==. sFile  E.^. SheetFileFile)
  E.on (sFile E.^. SheetFileSheet E.==. sheet  E.^. SheetId)
  E.on (sheet E.^. SheetCourse    E.==. course E.^. CourseId)
  -- filter to requested file
  E.where_ ((sheet  E.^. SheetName       E.==.  E.val shn      )
    E.&&.   (course E.^. CourseShorthand E.==.  E.val csh      )
    E.&&.   (course E.^. CourseSchool    E.==.  E.val ssh      )
    E.&&.   (course E.^. CourseTerm      E.==.  E.val tid      )
    E.&&.   (sFile  E.^. SheetFileType  `E.in_` E.valList sfts )
    )
  -- return file entity
  return file

-- | Check whether a sheet has any files for a given file type
hasSheetFileQuery :: Database.Esqueleto.Internal.Language.From query expr backend (expr (Entity SheetFile))
  => expr (Entity Sheet) -> SheetFileType -> expr (E.Value Bool)
hasSheetFileQuery sheet sft =
  E.exists $ E.from $ \sFile ->
    E.where_ ((sFile E.^. SheetFileSheet E.==. sheet E.^. SheetId)
      E.&&.   (sFile E.^. SheetFileType  E.==. E.val sft  ))
