module Sqel.SOP.Constraint where

import Data.Generics.Labels ()
import Generics.SOP (All, All2, Top)
import Generics.SOP.Constraint (Head)
import Generics.SOP.GGP (GCode, GDatatypeInfoOf, GFrom, GTo)
import Generics.SOP.Type.Metadata (DatatypeInfo (ADT, Newtype))

type Coded (d :: Type) (dss :: [[Type]]) =
  GCode d ~ dss

type ProductGCode d =
  Head (GCode d)

type ProductCoded (d :: Type) (ds :: [Type]) =
  Coded d '[ds]

type ReifySOP (d :: Type) (dss :: [[Type]]) =
  (Generic d, GTo d, GCode d ~ dss, All2 Top dss)

type ConstructSOP (d :: Type) (dss :: [[Type]]) =
  (Generic d, GFrom d, GCode d ~ dss, All2 Top dss)

type ReifyProd d ds =
  ReifySOP d '[ds]

type ConstructProd d ds =
  ConstructSOP d '[ds]

type IsNullary =
  (~) '[]

type IsEnum a =
  All IsNullary (GCode a)

type family DatatypeInfoName (dt :: DatatypeInfo) :: Symbol where
  DatatypeInfoName ('ADT _ name _ _) = name
  DatatypeInfoName ('Newtype _ name _) = name

type family DataName (d :: Type) :: Symbol where
  DataName d = DatatypeInfoName (GDatatypeInfoOf d)

symbolString ::
   (name :: Symbol) .
  KnownSymbol name =>
  String
symbolString :: forall (name :: Symbol). KnownSymbol name => String
symbolString =
  forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (forall {k} (t :: k). Proxy t
Proxy @name)

symbolText ::
   (name :: Symbol) .
  KnownSymbol name =>
  Text
symbolText :: forall (name :: Symbol). KnownSymbol name => Text
symbolText =
  forall a. ToText a => a -> Text
toText (forall (name :: Symbol). KnownSymbol name => String
symbolString @name)