content: {-# LANGUAGE DataKinds #-}
  {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
  
  {-
    These examples are simply provided to show what must compile
  -}
  module Test.Data.Registry.SimpleExamples where
  
  import Data.Registry
  import Data.Text as T (length)
  import Protolude hiding (C1)
  
  -- | No typeclass instance is necessary for a "record of functions" to be a Registry component
  data Logging = Logging
    { info :: Text -> IO (),
      debug :: Text -> IO ()
    }
  
  logging = make @Logging (fun Logging {info = print, debug = print} +: end)
  
  -- | Simple datatypes which can be used in a registry
  newtype Text1 = Text1 Text deriving (Eq, Show)
  
  newtype Text2 = Text2 Text deriving (Eq, Show)
  
  newtype Int1 = Int1 Int deriving (Eq, Show)
  
  -- | values and functions
  int1 :: Int
  int1 = 1
  
  add1 :: Int -> Text
  add1 i = show (i + 1)
  
  add2 :: Int -> Text -> Text1
  add2 i j = Text1 (show (i + 1) <> j)
  
  text1 :: Text
  text1 = "text1"
  
  toText2 :: Text1 -> Text2
  toText2 (Text1 t) = Text2 t
  
  registry1 :: Registry [Text1, Text, Int] [Text2, Text1, Text, Int]
  registry1 =
    normalize $
      fun toText2
        <: fun add2
        <: fun text1
        <: fun add1
        <: val int1
  
  countSize :: Text -> Maybe Int
  countSize t = Just (T.length t)
  
  made1 :: Text
  made1 = make @Text registry1
  
  made2 :: Text1
  made2 = make @Text1 registry1
  
  made3 :: Text2
  made3 = make @Text2 registry1
  
  --
  countSize1 :: Text -> Int1
  countSize1 t = Int1 (T.length t)
  
  registry2 =
    fun countSize1
      <: fun add1
      <: fun int1
  
  made4 :: Int1
  made4 = make @Int1 registry2
  
  -- | This does *not* compile because Double in not in the
  --   list of outputs for registry2
  
  {-
  wrong :: Double
  wrong = make @Double registry2
  -}
  
  -- | This does *not* compile because the list of inputs
  --   in registry2 is not included in the list of outputs
  unknown :: Double -> Text1
  unknown _ = Text1 "text1"
  
  -- | This does not compile because we need a double
  --   to make Text1 and it is not in the list of outputs
  
  {-
  registry3 :: Registry [Double, Int, Text] [Int, Text1, Text, Int1]
  registry3 =
       fun countSize1
    <: fun unknown
    <: fun add1
    <: val int1
  -}
  
  -- | Example with an optional configuration
  --   The ProductionComponent will only be used if the ServiceConfig says we are in production
  newtype ProductionComponent = ProductionComponent {doItInProduction :: IO ()}
  
  data ProductionConfig = ProductionConfig deriving (Eq, Show)
  
  newtype Service = Service {service :: IO ()}
  
  data ServiceConfig = InProd | InDev deriving (Eq, Show)
  
  -- | Production component definition
  
  -- Normal constructor
  newProductionComponent :: ProductionConfig -> Logging -> ProductionComponent
  newProductionComponent _ _ = ProductionComponent (pure ())
  
  -- Constructor which returns a "builder function", only used if a `ProductionConfig` is available
  newProductionComponentBuilder :: Logging -> Tag "builder" (ProductionConfig -> ProductionComponent)
  newProductionComponentBuilder = Tag . flip newProductionComponent
  
  -- | Service component definition
  --   It uses a builder for the ProductionComponent and only uses it in production
  newService :: ServiceConfig -> Tag "builder" (ProductionConfig -> ProductionComponent) -> Service
  newService InDev _ = Service {service = print ("dev" :: Text)}
  newService InProd f = Service {service = doItInProduction (unTag f ProductionConfig)}
  
  registryWithOptionalComponents =
    fun newService
      <: fun newProductionComponentBuilder
      <: fun logging
      <: val InDev
  
  makeService = make @Service registryWithOptionalComponents
  