{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.Morpheus.NamedResolvers
  ( ResolveNamed (..),
    NamedResolverT (..),
    resolve,
  )
where

import Data.Aeson (ToJSON)
import Data.Morpheus.Types.ID (ID)
import Relude

instance Monad m => ResolveNamed m ID where
  type Dep ID = ID
  resolveNamed :: Dep ID -> m ID
resolveNamed = Dep ID -> m ID
forall (f :: * -> *) a. Applicative f => a -> f a
pure

instance Monad m => ResolveNamed m Text where
  type Dep Text = Text
  resolveNamed :: Dep Text -> m Text
resolveNamed = Dep Text -> m Text
forall (f :: * -> *) a. Applicative f => a -> f a
pure

class (ToJSON (Dep a)) => ResolveNamed (m :: Type -> Type) a where
  type Dep a :: Type
  resolveNamed :: Monad m => Dep a -> m a

instance (ResolveNamed m a) => ResolveNamed (m :: Type -> Type) (Maybe a) where
  type Dep (Maybe a) = Maybe (Dep a)
  resolveNamed :: Dep (Maybe a) -> m (Maybe a)
resolveNamed (Just x) = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> m a -> m (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dep a -> m a
forall (m :: * -> *) a. (ResolveNamed m a, Monad m) => Dep a -> m a
resolveNamed Dep a
x
  resolveNamed Dep (Maybe a)
Nothing = Maybe a -> m (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing

instance (ResolveNamed m a) => ResolveNamed (m :: Type -> Type) [a] where
  type Dep [a] = [Dep a]
  resolveNamed :: Dep [a] -> m [a]
resolveNamed = (Dep a -> m a) -> [Dep a] -> m [a]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Dep a -> m a
forall (m :: * -> *) a. (ResolveNamed m a, Monad m) => Dep a -> m a
resolveNamed

data NamedResolverT (m :: Type -> Type) a where
  Ref :: ResolveNamed m a => m (Dep a) -> NamedResolverT m a
  Refs :: ResolveNamed m a => m [Dep a] -> NamedResolverT m [a]
  Value :: m a -> NamedResolverT m a

-- RESOLVER TYPES
data RES = VALUE | LIST | REF

type family RES_TYPE a b :: RES where
  RES_TYPE a a = 'VALUE
  RES_TYPE [a] [b] = 'LIST
  RES_TYPE a b = 'REF

resolve :: forall m a b. (ResolveByType (RES_TYPE a b) m a b) => Monad m => m a -> NamedResolverT m b
resolve :: m a -> NamedResolverT m b
resolve = Proxy (RES_TYPE a b) -> m a -> NamedResolverT m b
forall (k :: RES) (m :: * -> *) a b (f :: RES -> *).
(ResolveByType k m a b, Monad m) =>
f k -> m a -> NamedResolverT m b
resolveByType (Proxy (RES_TYPE a b)
forall k (t :: k). Proxy t
Proxy :: Proxy (RES_TYPE a b))

class Dep b ~ a => ResolveByType (k :: RES) m a b where
  resolveByType :: Monad m => f k -> m a -> NamedResolverT m b

instance (ResolveNamed m a, Dep a ~ a) => ResolveByType 'VALUE m a a where
  resolveByType :: f 'VALUE -> m a -> NamedResolverT m a
resolveByType f 'VALUE
_ = m a -> NamedResolverT m a
forall (m :: * -> *) a. m a -> NamedResolverT m a
Value

instance (ResolveNamed m b, Dep b ~ a) => ResolveByType 'LIST m [a] [b] where
  resolveByType :: f 'LIST -> m [a] -> NamedResolverT m [b]
resolveByType f 'LIST
_ = m [a] -> NamedResolverT m [b]
forall (m :: * -> *) a.
ResolveNamed m a =>
m [Dep a] -> NamedResolverT m [a]
Refs

instance (ResolveNamed m b, Dep b ~ a) => ResolveByType 'REF m a b where
  resolveByType :: f 'REF -> m a -> NamedResolverT m b
resolveByType f 'REF
_ = m a -> NamedResolverT m b
forall (m :: * -> *) a.
ResolveNamed m a =>
m (Dep a) -> NamedResolverT m a
Ref