module Handler.Utils.Corrections where

import Import


-- CorrectionInfo has seeming redundancies, but these are useful for aggregation
-- INVARIANT: isJust ciTot `implies` ciCorrected > 0
data CorrectionInfo = CorrectionInfo
      { ciSubmittors, ciSubmissions, ciAssigned, ciCorrected :: Integer
      , ciCorrector :: Maybe UserId
      , ciTot, ciMin,  ciMax :: Maybe NominalDiffTime
      }

instance Semigroup CorrectionInfo where
  corrA <> corrB =
        assert (isJust (ciTot corrA) `implies` (ciCorrected corrA > 0)) $
        assert (isJust (ciTot corrB) `implies` (ciCorrected corrB > 0))
        CorrectionInfo
          { ciSubmittors  = ciSubmittors  `mergeWith` (+)
          , ciSubmissions = ciSubmissions `mergeWith` (+)
          , ciAssigned    = ciAssigned    `mergeWith` (+)
          , ciCorrected   = ciCorrected   `mergeWith` (+)
          , ciCorrector   = ciCorrector   `mergeWith` keepEqual
          , ciTot         = ciTot `mergeWith` ignoreNothing (+)
          , ciMin         = ciMin `mergeWith` ignoreNothing min
          , ciMax         = ciMax `mergeWith` ignoreNothing max
          }
    where
      mergeWith :: (CorrectionInfo -> a) -> (a -> a -> c) -> c
      mergeWith prj f = on f prj corrA corrB

      keepEqual (Just x) (Just y) | x==y = Just x
      keepEqual Nothing other = other
      keepEqual other Nothing = other
      keepEqual _ _ = Nothing

instance Monoid CorrectionInfo where
  mappend = (<>)
  mempty  = CorrectionInfo  { ciSubmittors  = 0
                            , ciSubmissions = 0
                            , ciAssigned    = 0
                            , ciCorrected   = 0
                            , ciCorrector   = Nothing
                            , ciMin         = Nothing
                            , ciTot         = Nothing
                            , ciMax         = Nothing
                            }
