{-# LANGUAGE AllowAmbiguousTypes   #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications      #-}

module PlutusTx.Blueprint.Class where

import Prelude hiding (maximum, minimum)

import Data.Kind (Type)
import PlutusTx.Blueprint.Schema (PairSchema (..), Schema (..), emptyBytesSchema,
                                  emptyIntegerSchema)
import PlutusTx.Blueprint.Schema.Annotation (emptySchemaInfo)
import PlutusTx.Builtins (BuiltinByteString, BuiltinData, BuiltinString)

{- |
  A class of types that have a Blueprint schema definition
  and can reference other schema definitions of other types.
-}
class HasSchema (t :: Type) (referencedTypes :: [Type]) where
  schema :: Schema referencedTypes

instance HasSchema () ts where
  schema :: Schema ts
schema = SchemaInfo -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> Schema referencedTypes
SchemaBuiltInUnit SchemaInfo
emptySchemaInfo

instance HasSchema Integer ts where
  schema :: Schema ts
schema = SchemaInfo -> IntegerSchema -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> IntegerSchema -> Schema referencedTypes
SchemaInteger SchemaInfo
emptySchemaInfo IntegerSchema
emptyIntegerSchema

instance HasSchema BuiltinByteString ts where
  schema :: Schema ts
schema = SchemaInfo -> BytesSchema -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> BytesSchema -> Schema referencedTypes
SchemaBytes SchemaInfo
emptySchemaInfo BytesSchema
emptyBytesSchema

instance HasSchema Bool ts where
  schema :: Schema ts
schema = SchemaInfo -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> Schema referencedTypes
SchemaBuiltInBoolean SchemaInfo
emptySchemaInfo

instance HasSchema BuiltinString ts where
  schema :: Schema ts
schema = SchemaInfo -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> Schema referencedTypes
SchemaBuiltInString SchemaInfo
emptySchemaInfo

instance HasSchema BuiltinData ts where
  schema :: Schema ts
schema = SchemaInfo -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> Schema referencedTypes
SchemaBuiltInData SchemaInfo
emptySchemaInfo

instance (HasSchema a ts, HasSchema b ts) => HasSchema (a, b) ts where
  schema :: Schema ts
schema =
    SchemaInfo -> PairSchema ts -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> PairSchema referencedTypes -> Schema referencedTypes
SchemaBuiltInPair
      SchemaInfo
emptySchemaInfo
      MkPairSchema{$sel:left:MkPairSchema :: Schema ts
left = forall t (referencedTypes :: [*]).
HasSchema t referencedTypes =>
Schema referencedTypes
schema @a @ts, $sel:right:MkPairSchema :: Schema ts
right = forall t (referencedTypes :: [*]).
HasSchema t referencedTypes =>
Schema referencedTypes
schema @b @ts}

instance (HasSchema a ts) => HasSchema [a] ts where
  schema :: Schema ts
schema = SchemaInfo -> Schema ts -> Schema ts
forall (referencedTypes :: [*]).
SchemaInfo -> Schema referencedTypes -> Schema referencedTypes
SchemaBuiltInList SchemaInfo
emptySchemaInfo (forall t (referencedTypes :: [*]).
HasSchema t referencedTypes =>
Schema referencedTypes
schema @a @ts)