content: {-# LANGUAGE AllowAmbiguousTypes #-}
  {-# LANGUAGE ConstraintKinds #-}
  {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE PolyKinds #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module Data.Morpheus.Server.Deriving.Utils.GScan
    ( scanFree,
      FreeCatType (..),
      freeLeaf,
      freeNode,
      ScanRef,
    )
  where
  
  import Data.Morpheus.Generic
    ( CBox,
      Gmap,
      ProxyMap (..),
      ScanRef (..),
      scan,
    )
  import Data.Morpheus.Server.Deriving.Utils.Kinded (mapCat)
  import Data.Morpheus.Server.Deriving.Utils.Types (CatType (..))
  import Data.Morpheus.Server.Types.TypeName (TypeFingerprint (..))
  import GHC.Generics (Generic (Rep))
  import Relude hiding (fromList)
  
  instance ProxyMap FreeCatType where
    proxyMap prx (FreeCatType cat) = FreeCatType (mapCat prx cat)
  
  data FreeCatType a where
    FreeCatType :: forall c a. CatType c a -> FreeCatType a
  
  freeLeaf :: (c1 a) => TypeFingerprint -> CatType c2 a -> ScanRef FreeCatType c1
  freeLeaf fp p = ScanLeaf (show fp) (FreeCatType p)
  
  freeNode :: (c a, Gmap c (Rep a)) => Bool -> TypeFingerprint -> CatType c2 a -> ScanRef FreeCatType c
  freeNode visible fp p = ScanNode visible (show fp) (FreeCatType p)
  
  scanFree :: (c a) => (forall k' a'. (c a') => CatType k' a' -> [ScanRef FreeCatType c]) -> CatType k a -> [CBox FreeCatType c]
  scanFree f = scan (\(FreeCatType x) -> f x) . FreeCatType
  