{-# LANGUAGE GADTs #-}
module Cardano.CLI.Shelley.Run.Address.Info
  ( runAddressInfo
  , ShelleyAddressInfoError(..)
  ) where

import           Cardano.Api
import           Cardano.CLI.Shelley.Parsers (OutputFile (..))

import           Control.Monad.IO.Class (MonadIO (..))
import           Control.Monad.Trans.Except (ExceptT)
import           Control.Monad.Trans.Except.Extra (left)
import           Data.Aeson (ToJSON (..), object, (.=))
import           Data.Aeson.Encode.Pretty (encodePretty)
import qualified Data.ByteString.Lazy.Char8 as LBS
import           Data.Text (Text)
import           Options.Applicative (Alternative (..))

newtype ShelleyAddressInfoError = ShelleyAddressInvalid Text
  deriving Int -> ShelleyAddressInfoError -> ShowS
[ShelleyAddressInfoError] -> ShowS
ShelleyAddressInfoError -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ShelleyAddressInfoError] -> ShowS
$cshowList :: [ShelleyAddressInfoError] -> ShowS
show :: ShelleyAddressInfoError -> String
$cshow :: ShelleyAddressInfoError -> String
showsPrec :: Int -> ShelleyAddressInfoError -> ShowS
$cshowsPrec :: Int -> ShelleyAddressInfoError -> ShowS
Show

instance Error ShelleyAddressInfoError where
  displayError :: ShelleyAddressInfoError -> String
displayError (ShelleyAddressInvalid Text
addrTxt) =
    String
"Invalid address: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show Text
addrTxt

data AddressInfo = AddressInfo
  { AddressInfo -> Text
aiType :: !Text
  , AddressInfo -> Text
aiEra :: !Text
  , AddressInfo -> Text
aiEncoding :: !Text
  , AddressInfo -> Text
aiAddress :: !Text
  , AddressInfo -> Text
aiBase16 :: !Text
  }

instance ToJSON AddressInfo where
  toJSON :: AddressInfo -> Value
toJSON AddressInfo
addrInfo =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiType AddressInfo
addrInfo
      , Key
"era" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiEra AddressInfo
addrInfo
      , Key
"encoding" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiEncoding AddressInfo
addrInfo
      , Key
"address" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiAddress AddressInfo
addrInfo
      , Key
"base16" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiBase16 AddressInfo
addrInfo
      ]

runAddressInfo :: Text -> Maybe OutputFile -> ExceptT ShelleyAddressInfoError IO ()
runAddressInfo :: Text -> Maybe OutputFile -> ExceptT ShelleyAddressInfoError IO ()
runAddressInfo Text
addrTxt Maybe OutputFile
mOutputFp = do
    AddressInfo
addrInfo <- case (forall a b. a -> Either a b
Left  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall addr.
SerialiseAddress addr =>
AsType addr -> Text -> Maybe addr
deserialiseAddress AsType AddressAny
AsAddressAny Text
addrTxt)
                 forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (forall a b. b -> Either a b
Right forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall addr.
SerialiseAddress addr =>
AsType addr -> Text -> Maybe addr
deserialiseAddress AsType StakeAddress
AsStakeAddress Text
addrTxt) of

      Maybe (Either AddressAny StakeAddress)
Nothing ->
        forall (m :: * -> *) x a. Monad m => x -> ExceptT x m a
left forall a b. (a -> b) -> a -> b
$ Text -> ShelleyAddressInfoError
ShelleyAddressInvalid Text
addrTxt

      Just (Left (AddressByron Address ByronAddr
payaddr)) ->
            forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ AddressInfo
              { aiType :: Text
aiType = Text
"payment"
              , aiEra :: Text
aiEra = Text
"byron"
              , aiEncoding :: Text
aiEncoding = Text
"base58"
              , aiAddress :: Text
aiAddress = Text
addrTxt
              , aiBase16 :: Text
aiBase16 = forall a. SerialiseAsRawBytes a => a -> Text
serialiseToRawBytesHexText Address ByronAddr
payaddr
              }

      Just (Left (AddressShelley Address ShelleyAddr
payaddr)) ->
            forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ AddressInfo
              { aiType :: Text
aiType = Text
"payment"
              , aiEra :: Text
aiEra = Text
"shelley"
              , aiEncoding :: Text
aiEncoding = Text
"bech32"
              , aiAddress :: Text
aiAddress = Text
addrTxt
              , aiBase16 :: Text
aiBase16 = forall a. SerialiseAsRawBytes a => a -> Text
serialiseToRawBytesHexText Address ShelleyAddr
payaddr
              }

      Just (Right StakeAddress
addr) ->
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ AddressInfo
          { aiType :: Text
aiType = Text
"stake"
          , aiEra :: Text
aiEra = Text
"shelley"
          , aiEncoding :: Text
aiEncoding = Text
"bech32"
          , aiAddress :: Text
aiAddress = Text
addrTxt
          , aiBase16 :: Text
aiBase16 = forall a. SerialiseAsRawBytes a => a -> Text
serialiseToRawBytesHexText StakeAddress
addr
          }

    case Maybe OutputFile
mOutputFp of
      Just (OutputFile String
fpath) -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ String -> ByteString -> IO ()
LBS.writeFile String
fpath forall a b. (a -> b) -> a -> b
$ forall a. ToJSON a => a -> ByteString
encodePretty AddressInfo
addrInfo
      Maybe OutputFile
Nothing -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ ByteString -> IO ()
LBS.putStrLn forall a b. (a -> b) -> a -> b
$ forall a. ToJSON a => a -> ByteString
encodePretty AddressInfo
addrInfo