module Plutarch.Extra.ExchangeRate (
  type (:>),

  -- * Exchange-rate conversions
  exchangeFromTruncate,
  exchangeToTruncate,
  exchangeFrom,
  exchangeTo,
) where

import GHC.TypeLits (Symbol)
import Plutarch.Extra.Applicative (ppure)
import Plutarch.Extra.Comonad (pextract)
import Plutarch.Extra.Rational (divRational, divTruncate, mulRational, mulTruncate)
import Plutarch.Extra.Tagged (PTagged)

{- | Represents an exchange from @a@ to @b@.

     For example, suppose 1.00 ADA is worth 2.00 USD. Then @ADA ':>' USD@
     represents scaling by 2.0.

   @since 3.9.0
-}
data (:>) (a :: Symbol) (b :: Symbol)

{- | Exchange from one currency to another, truncating the result.

 @since 3.9.0
-}
exchangeFromTruncate ::
  forall (a :: Symbol) (b :: Symbol) (s :: S).
  Term
    s
    ( PTagged (a :> b) PRational
        :--> PTagged a PInteger
        :--> PTagged b PInteger
    )
exchangeFromTruncate :: forall (a :: Symbol) (b :: Symbol) (s :: S).
Term
  s
  (PTagged (a :> b) PRational
   :--> (PTagged a PInteger :--> PTagged b PInteger))
exchangeFromTruncate =
  forall (a :: PType) (s :: S).
HasCallStack =>
ClosedTerm a -> Term s a
phoistAcyclic forall a b. (a -> b) -> a -> b
$
    forall a (b :: PType) (s :: S) (c :: PType).
(PLamN a b s, HasCallStack) =>
(Term s c -> a) -> Term s (c :--> b)
plam forall a b. (a -> b) -> a -> b
$
      \Term s (PTagged (a :> b) PRational)
ex Term s (PTagged a PInteger)
x -> forall (f :: PType -> PType) (a :: PType) (s :: S).
(PApplicative f, PSubcategory f a) =>
Term s (a :--> f a)
ppure forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
#$ forall (s :: S). Term s (PRational :--> (PInteger :--> PInteger))
mulTruncate forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# forall (s :: S) (a :: PType). Term s a -> Term s (PInner a)
pto Term s (PTagged (a :> b) PRational)
ex forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# forall (s :: S) (a :: PType). Term s a -> Term s (PInner a)
pto Term s (PTagged a PInteger)
x

{- | Exchange from  one currency to another, truncating the result
 (inverse direction).

 @since 3.9.0
-}
exchangeToTruncate ::
  forall (a :: Symbol) (b :: Symbol) (s :: S).
  Term
    s
    ( PTagged (a :> b) PRational
        :--> PTagged b PInteger
        :--> PTagged a PInteger
    )
exchangeToTruncate :: forall (a :: Symbol) (b :: Symbol) (s :: S).
Term
  s
  (PTagged (a :> b) PRational
   :--> (PTagged b PInteger :--> PTagged a PInteger))
exchangeToTruncate =
  forall (a :: PType) (s :: S).
HasCallStack =>
ClosedTerm a -> Term s a
phoistAcyclic forall a b. (a -> b) -> a -> b
$
    forall a (b :: PType) (s :: S) (c :: PType).
(PLamN a b s, HasCallStack) =>
(Term s c -> a) -> Term s (c :--> b)
plam forall a b. (a -> b) -> a -> b
$ \Term s (PTagged (a :> b) PRational)
ex Term s (PTagged b PInteger)
x ->
      forall (f :: PType -> PType) (a :: PType) (s :: S).
(PApplicative f, PSubcategory f a) =>
Term s (a :--> f a)
ppure forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
#$ forall (s :: S). Term s (PRational :--> (PInteger :--> PInteger))
divTruncate forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# (forall (w :: PType -> PType) (a :: PType) (s :: S).
(PComonad w, PSubcategory w a) =>
Term s (w a :--> a)
pextract forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# Term s (PTagged (a :> b) PRational)
ex) forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# (forall (w :: PType -> PType) (a :: PType) (s :: S).
(PComonad w, PSubcategory w a) =>
Term s (w a :--> a)
pextract forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# Term s (PTagged b PInteger)
x)

{- | Convert between quantities of currencies using a 'PRational' conversion
  value.

 @since 3.9.0
-}
exchangeFrom ::
  forall (a :: Symbol) (b :: Symbol) (s :: S).
  Term
    s
    ( PTagged (a :> b) PRational
        :--> PTagged a PInteger
        :--> PTagged b PRational
    )
exchangeFrom :: forall (a :: Symbol) (b :: Symbol) (s :: S).
Term
  s
  (PTagged (a :> b) PRational
   :--> (PTagged a PInteger :--> PTagged b PRational))
exchangeFrom =
  forall (a :: PType) (s :: S).
HasCallStack =>
ClosedTerm a -> Term s a
phoistAcyclic forall a b. (a -> b) -> a -> b
$
    forall a (b :: PType) (s :: S) (c :: PType).
(PLamN a b s, HasCallStack) =>
(Term s c -> a) -> Term s (c :--> b)
plam forall a b. (a -> b) -> a -> b
$ \Term s (PTagged (a :> b) PRational)
ex Term s (PTagged a PInteger)
x ->
      forall (f :: PType -> PType) (a :: PType) (s :: S).
(PApplicative f, PSubcategory f a) =>
Term s (a :--> f a)
ppure forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
#$ forall (s :: S). Term s (PInteger :--> (PRational :--> PRational))
mulRational forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# (forall (w :: PType -> PType) (a :: PType) (s :: S).
(PComonad w, PSubcategory w a) =>
Term s (w a :--> a)
pextract forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# Term s (PTagged a PInteger)
x) forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# (forall (w :: PType -> PType) (a :: PType) (s :: S).
(PComonad w, PSubcategory w a) =>
Term s (w a :--> a)
pextract forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# Term s (PTagged (a :> b) PRational)
ex)

{- | Convert between quantities of currencies, in the inverse direction.

 @since 3.9.0
-}
exchangeTo ::
  forall (a :: Symbol) (b :: Symbol) (s :: S).
  Term
    s
    ( PTagged (a :> b) PRational
        :--> PTagged b PInteger
        :--> PTagged a PRational
    )
exchangeTo :: forall (a :: Symbol) (b :: Symbol) (s :: S).
Term
  s
  (PTagged (a :> b) PRational
   :--> (PTagged b PInteger :--> PTagged a PRational))
exchangeTo =
  forall (a :: PType) (s :: S).
HasCallStack =>
ClosedTerm a -> Term s a
phoistAcyclic forall a b. (a -> b) -> a -> b
$
    forall a (b :: PType) (s :: S) (c :: PType).
(PLamN a b s, HasCallStack) =>
(Term s c -> a) -> Term s (c :--> b)
plam forall a b. (a -> b) -> a -> b
$ \Term s (PTagged (a :> b) PRational)
ex Term s (PTagged b PInteger)
x ->
      forall (f :: PType -> PType) (a :: PType) (s :: S).
(PApplicative f, PSubcategory f a) =>
Term s (a :--> f a)
ppure forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
#$ forall (s :: S). Term s (PInteger :--> (PRational :--> PRational))
divRational forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# (forall (w :: PType -> PType) (a :: PType) (s :: S).
(PComonad w, PSubcategory w a) =>
Term s (w a :--> a)
pextract forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# Term s (PTagged b PInteger)
x) forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# (forall (w :: PType -> PType) (a :: PType) (s :: S).
(PComonad w, PSubcategory w a) =>
Term s (w a :--> a)
pextract forall (s :: S) (a :: PType) (b :: PType).
HasCallStack =>
Term s (a :--> b) -> Term s a -> Term s b
# Term s (PTagged (a :> b) PRational)
ex)