content: {-# LANGUAGE AllowAmbiguousTypes #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# OPTIONS_GHC -Wno-orphans #-}
  
  module Ema.Route.Generic.SubModel (
    HasSubModels (subModels),
    -- DerivingVia types
    GSubModels (..),
  ) where
  
  import Data.Generics.Product (HasAny (the))
  import Ema.Route.Class (IsRoute (RouteModel))
  import Ema.Route.Generic.SubRoute (HasSubRoutes (SubRoutes))
  import Ema.Route.Lib.Multi (MultiModel)
  import Generics.SOP (I (..), NP (Nil, (:*)))
  import Optics.Core (united, view)
  import Prelude hiding (All)
  
  class (HasSubRoutes r) => HasSubModels r where
    -- | Break the model into a list of sub-models used correspondingly by the sub-routes.
    subModels :: RouteModel r -> NP I (MultiModel (SubRoutes r))
  
  class GSubModels m (ms :: [Type]) (lookups :: [k]) where
    gsubModels :: m -> NP I ms
  
  instance GSubModels m '[] '[] where
    gsubModels _ = Nil
  
  instance
    {-# OVERLAPPING #-}
    (HasAny s m m t t, GSubModels m ms ss) =>
    GSubModels m (t ': ms) (s ': ss)
    where
    gsubModels m = I (view (the @s @m @_ @t @_) m) :* gsubModels @_ @m @ms @ss m
  
  -- Useful instances to support varied types in `WithSubModels` list.
  
  instance {-# OVERLAPPING #-} HasAny () s s () () where
    the = united
  
  instance (HasAny sel s t a b) => HasAny (Proxy sel) s t a b where
    the = the @sel
  