{-# LANGUAGE NamedFieldPuns #-}

module Data.Morpheus.Validation.Spread
  ( getFragment
  , resolveSpread
  , castFragmentType
  ) where

import qualified Data.Map                                      as M (lookup)
import           Data.Morpheus.Error.Spread                    (cannotBeSpreadOnType, unknownFragment)
import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, Reference (..))
import           Data.Morpheus.Types.Internal.Base             (Position)
import           Data.Morpheus.Types.Internal.Validation       (Validation)
import           Data.Text                                     (Text)
import qualified Data.Text                                     as T (concat)

getFragment :: Reference -> FragmentLib -> Validation Fragment
getFragment Reference {referenceName, referencePosition} lib =
  case M.lookup referenceName lib of
    Nothing       -> Left $ unknownFragment referenceName referencePosition
    Just fragment -> pure fragment

castFragmentType :: Maybe Text -> Position -> [Text] -> Fragment -> Validation Fragment
castFragmentType key' position' targets' fragment@Fragment {fragmentType = type'} =
  if type' `elem` targets'
    then pure fragment
    else Left $ cannotBeSpreadOnType key' type' position' (T.concat targets')

resolveSpread :: FragmentLib -> [Text] -> Reference -> Validation Fragment
resolveSpread fragments' allowedTargets' reference@Reference {referenceName = key', referencePosition = position'} =
  getFragment reference fragments' >>= castFragmentType (Just key') position' allowedTargets'