{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

module Plutarch.Builtin.Integer (
  -- * Type
  PInteger,

  -- * Functions
  pexpModInteger,
  peqInteger,
  pleInteger,
  pltInteger,
  paddInteger,
  psubtractInteger,
  pmultiplyInteger,
  pconstantInteger,
  pquotientInteger,
  premainderInteger,
) where

import GHC.Generics (Generic)

-- import Plutarch.Internal.Lift (DeriveBuiltinPLiftable, PLiftable, PLifted (PLifted))
-- import Plutarch.Internal.Newtype (PlutusTypeNewtype)

import Plutarch.Builtin.Bool (PBool)
import Plutarch.Builtin.Opaque (POpaque)
import Plutarch.Internal.Term (S, Term, punsafeBuiltin, punsafeConstantInternal, (:-->))
import PlutusCore qualified as PLC

{- | A builtin Plutus integer.

@since WIP
-}
newtype PInteger s = PInteger (Term s POpaque)
  deriving stock ((forall x. PInteger s -> Rep (PInteger s) x)
-> (forall x. Rep (PInteger s) x -> PInteger s)
-> Generic (PInteger s)
forall x. Rep (PInteger s) x -> PInteger s
forall x. PInteger s -> Rep (PInteger s) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (s :: S) x. Rep (PInteger s) x -> PInteger s
forall (s :: S) x. PInteger s -> Rep (PInteger s) x
$cfrom :: forall (s :: S) x. PInteger s -> Rep (PInteger s) x
from :: forall x. PInteger s -> Rep (PInteger s) x
$cto :: forall (s :: S) x. Rep (PInteger s) x -> PInteger s
to :: forall x. Rep (PInteger s) x -> PInteger s
Generic)

{- | Performs modulo exponentiation. More precisely, @pexpModInteger b e m@
performs @b@ to the power of @e@, modulo @m@. The result is always
non-negative.

= Note

This will error if the modulus is zero. When given a negative exponent, this
will try to find a modular multiplicative inverse, and will error if none
exists.

@since WIP
-}
pexpModInteger ::
  forall (s :: S).
  Term s (PInteger :--> PInteger :--> PInteger :--> PInteger)
pexpModInteger :: forall (s :: S).
Term s (PInteger :--> (PInteger :--> (PInteger :--> PInteger)))
pexpModInteger = DefaultFun
-> Term s (PInteger :--> (PInteger :--> (PInteger :--> PInteger)))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.ExpModInteger

peqInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PBool)
peqInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PBool))
peqInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PBool))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.EqualsInteger

pleInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PBool)
pleInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PBool))
pleInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PBool))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.LessThanEqualsInteger

pltInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PBool)
pltInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PBool))
pltInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PBool))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.LessThanInteger

paddInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PInteger)
paddInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PInteger))
paddInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PInteger))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.AddInteger

psubtractInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PInteger)
psubtractInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PInteger))
psubtractInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PInteger))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.SubtractInteger

pmultiplyInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PInteger)
pmultiplyInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PInteger))
pmultiplyInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PInteger))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.MultiplyInteger

pconstantInteger :: forall (s :: S). Integer -> Term s PInteger
pconstantInteger :: forall (s :: S). Integer -> Term s PInteger
pconstantInteger = Some @Type (ValueOf DefaultUni) -> Term s PInteger
forall (s :: S) (a :: PType).
Some @Type (ValueOf DefaultUni) -> Term s a
punsafeConstantInternal (Some @Type (ValueOf DefaultUni) -> Term s PInteger)
-> (Integer -> Some @Type (ValueOf DefaultUni))
-> Integer
-> Term s PInteger
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Some @Type (ValueOf DefaultUni)
forall a (uni :: Type -> Type).
Contains @Type uni a =>
a -> Some @Type (ValueOf uni)
PLC.someValue

pquotientInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PInteger)
pquotientInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PInteger))
pquotientInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PInteger))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.QuotientInteger

premainderInteger :: forall (s :: S). Term s (PInteger :--> PInteger :--> PInteger)
premainderInteger :: forall (s :: S). Term s (PInteger :--> (PInteger :--> PInteger))
premainderInteger = DefaultFun -> Term s (PInteger :--> (PInteger :--> PInteger))
forall (s :: S) (a :: PType). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.RemainderInteger