{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE PartialTypeSignatures #-}
-- {-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}

-- |
-- Internal definition of types
--
-- Possible replacement for EncodeFAll class that works with open definitions such as "r-ban"

module Data.TypedEncoding.Internal.Class.Encoder where

import           Data.TypedEncoding.Internal.Types.Enc
-- import           Data.TypedEncoding.Internal.Class.Util
import           Data.TypedEncoding.Internal.Class.Encode
import           Data.TypedEncoding.Internal.Util.TypeLits
import           GHC.TypeLits
-- import           Data.Symbol.Ascii


data Encoder f (enc :: [Symbol]) (grps :: [Symbol]) conf str where
    -- | constructor is to be treated as Unsafe to Encode and Decode instance implementations
    -- particular encoding instances may expose smart constructors for limited data types
    ZeroEnc :: Encoder f '[] '[] conf str
    AppendEnc ::  (Enc xs conf str -> f (Enc (x ': xs) conf str)) -> Encoder f xs grps conf str -> Encoder f (x ': xs) ((TakeUntil x ":") ': grps) conf str

runEncoder :: forall grps enc f c str . (Monad f) => Encoder f enc grps c str -> Enc ('[]::[Symbol]) c str -> f (Enc enc c str)
runEncoder ZeroEnc enc0 = pure enc0
runEncoder (AppendEnc fn enc) enc0 =
        let re :: f (Enc _ c str) = runEncoder enc enc0
        in re >>= fn

encodeFEncoder :: forall f t tg xs gxs c str . (tg ~ TakeUntil t ":", Encodings f xs gxs c str, EncodeF f (Enc xs c str) (Enc (t ': xs) c str)) => Encoder f (t ': xs) (tg ': gxs) c str
encodeFEncoder = AppendEnc (encodeF @f @(Enc xs c str) @(Enc (t ': xs) c str)) encodings

class Encodings f (enc :: [Symbol]) (grps :: [Symbol]) c str where
    encodings :: Encoder f enc grps c str

instance Encodings f '[] '[] c str where
    encodings = ZeroEnc