module Cfg.Source.RootConfig where

import Cfg.Options (RootOptions (..))
import Cfg.Source.NestedConfig
import Data.Kind (Type)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Tree (Tree (..))
import GHC.Generics

defaultToRootConfig :: forall a. (Generic a, GConfigTree (Rep a)) => RootOptions -> Tree Text
defaultToRootConfig :: forall a.
(Generic a, GConfigTree (Rep a)) =>
RootOptions -> Tree Text
defaultToRootConfig RootOptions
opts = forall (a :: * -> *). GConfigTree a => RootOptions -> Tree Text
gToTree @(Rep a) RootOptions
opts

class GConfigTree (a :: Type -> Type) where
    gToTree :: RootOptions -> Tree Text

-- TODO: Investigate whether this is required or not. Theoretically don't need this?
--
-- instance RootConfig a => GConfigTree (K1 R a) where
--   gToTree opts _ = toRootConfig opts (Proxy @a)

instance GConfigTree f => GConfigTree (M1 S s f) where
    gToTree :: RootOptions -> Tree Text
gToTree RootOptions
opts = forall (a :: * -> *). GConfigTree a => RootOptions -> Tree Text
gToTree @f RootOptions
opts

instance GConfigTree f => GConfigTree (M1 D s f) where
    gToTree :: RootOptions -> Tree Text
gToTree RootOptions
opts = forall (a :: * -> *). GConfigTree a => RootOptions -> Tree Text
gToTree @f RootOptions
opts

instance (Constructor c, GConfigForest f) => GConfigTree (M1 C c f) where
    gToTree :: RootOptions -> Tree Text
gToTree RootOptions
opts
        | Any c f Any -> Bool
forall {k} (c :: k) k1 (t :: k -> (k1 -> *) -> k1 -> *)
       (f :: k1 -> *) (a :: k1).
Constructor c =>
t c f a -> Bool
forall k1 (t :: Meta -> (k1 -> *) -> k1 -> *) (f :: k1 -> *)
       (a :: k1).
t c f a -> Bool
conIsRecord Any c f Any
forall (t :: Meta -> (* -> *) -> * -> *) a. t c f a
m =
            Text -> [Tree Text] -> Tree Text
forall a. a -> [Tree a] -> Tree a
Node
                (RootOptions -> Text -> Text
rootOptionsLabelModifier RootOptions
opts (Text -> Text) -> ([Char] -> Text) -> [Char] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$ Any c f Any -> [Char]
forall {k} (c :: k) k1 (t :: k -> (k1 -> *) -> k1 -> *)
       (f :: k1 -> *) (a :: k1).
Constructor c =>
t c f a -> [Char]
forall k1 (t :: Meta -> (k1 -> *) -> k1 -> *) (f :: k1 -> *)
       (a :: k1).
t c f a -> [Char]
conName Any c f Any
forall (t :: Meta -> (* -> *) -> * -> *) a. t c f a
m)
                (forall (a :: * -> *).
GConfigForest a =>
ConfigOptions -> [Tree Text]
gToForest @f (ConfigOptions -> [Tree Text]) -> ConfigOptions -> [Tree Text]
forall a b. (a -> b) -> a -> b
$ RootOptions -> ConfigOptions
rootOptionsFieldOptions RootOptions
opts)
        | Bool
otherwise = [Char] -> Tree Text
forall a. HasCallStack => [Char] -> a
error [Char]
"Can only create a tree for named product types i.e. Records with named fields"
      where
        m :: t c f a
        m :: forall (t :: Meta -> (* -> *) -> * -> *) a. t c f a
m = t c f a
forall a. HasCallStack => a
undefined