module Model.Types.Allocation
  ( AllocationPriority(..)
  , AllocationPriorityComparison(..)
  , AllocationFingerprint
  , module Utils.Allocation
  ) where

import Import.NoModel
import Utils.Allocation (MatchingLog(..))
import Model.Types.Common

import qualified Data.Csv as Csv
import qualified Data.Vector as Vector

import qualified Data.Map.Strict as Map
  
import Crypto.Hash (Digest, SHAKE128)

{-# ANN module ("HLint: ignore Use newtype instead of data"::String) #-}


data AllocationPriority
  = AllocationPriorityNumeric { allocationPriorities :: Vector Integer }
  | AllocationPriorityOrdinal { allocationOrdinal :: Natural }
  deriving (Eq, Ord, Read, Show, Generic, Typeable)
deriveJSON defaultOptions
  { fieldLabelModifier = camelToPathPiece' 1
  , constructorTagModifier = camelToPathPiece' 2
  , allNullaryToStringTag = False
  , sumEncoding = TaggedObject "mode" "value"
  , unwrapUnaryRecords = False
  , tagSingleConstructors = True
  } ''AllocationPriority
derivePersistFieldJSON ''AllocationPriority

instance Binary AllocationPriority

instance Csv.FromRecord (Map UserMatriculation AllocationPriority) where
  parseRecord v = parseNumeric
    where
      parseNumeric
        | Vector.length v >= 1 = Map.singleton <$> v Csv..! 0 <*> (AllocationPriorityNumeric <$> mapM Csv.parseField (Vector.tail v))
        | otherwise = mzero


data AllocationPriorityComparison
  = AllocationPriorityComparisonNumeric { allocationGradeScale :: Rational }
  | AllocationPriorityComparisonOrdinal { allocationCloneIndex :: Down Natural, allocationOrdinalScale :: Rational }
  deriving (Eq, Ord, Read, Show, Generic, Typeable)


type AllocationFingerprint = Digest (SHAKE128 128)
