{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}

module Cardano.CLI.Run.Address.Info
  ( runAddressInfoCmd
  )
where

import           Cardano.Api

import           Cardano.CLI.Types.Errors.AddressInfoError

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 (..))

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" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiType AddressInfo
addrInfo
      , Key
"era" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiEra AddressInfo
addrInfo
      , Key
"encoding" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiEncoding AddressInfo
addrInfo
      , Key
"address" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiAddress AddressInfo
addrInfo
      , Key
"base16" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= AddressInfo -> Text
aiBase16 AddressInfo
addrInfo
      ]

runAddressInfoCmd :: Text -> Maybe (File () Out) -> ExceptT AddressInfoError IO ()
runAddressInfoCmd :: Text -> Maybe (File () 'Out) -> ExceptT AddressInfoError IO ()
runAddressInfoCmd Text
addrTxt Maybe (File () 'Out)
mOutputFp = do
  AddressInfo
addrInfo <- case (AddressAny -> Either AddressAny StakeAddress
forall a b. a -> Either a b
Left (AddressAny -> Either AddressAny StakeAddress)
-> Maybe AddressAny -> Maybe (Either AddressAny StakeAddress)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AsType AddressAny -> Text -> Maybe AddressAny
forall addr.
SerialiseAddress addr =>
AsType addr -> Text -> Maybe addr
deserialiseAddress AsType AddressAny
AsAddressAny Text
addrTxt)
    Maybe (Either AddressAny StakeAddress)
-> Maybe (Either AddressAny StakeAddress)
-> Maybe (Either AddressAny StakeAddress)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (StakeAddress -> Either AddressAny StakeAddress
forall a b. b -> Either a b
Right (StakeAddress -> Either AddressAny StakeAddress)
-> Maybe StakeAddress -> Maybe (Either AddressAny StakeAddress)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AsType StakeAddress -> Text -> Maybe StakeAddress
forall addr.
SerialiseAddress addr =>
AsType addr -> Text -> Maybe addr
deserialiseAddress AsType StakeAddress
AsStakeAddress Text
addrTxt) of
    Maybe (Either AddressAny StakeAddress)
Nothing ->
      AddressInfoError -> ExceptT AddressInfoError IO AddressInfo
forall (m :: * -> *) x a. Monad m => x -> ExceptT x m a
left (AddressInfoError -> ExceptT AddressInfoError IO AddressInfo)
-> AddressInfoError -> ExceptT AddressInfoError IO AddressInfo
forall a b. (a -> b) -> a -> b
$ Text -> AddressInfoError
ShelleyAddressInvalid Text
addrTxt
    Just (Left (AddressByron Address ByronAddr
payaddr)) ->
      AddressInfo -> ExceptT AddressInfoError IO AddressInfo
forall a. a -> ExceptT AddressInfoError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (AddressInfo -> ExceptT AddressInfoError IO AddressInfo)
-> AddressInfo -> ExceptT AddressInfoError IO AddressInfo
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 = Address ByronAddr -> Text
forall a. SerialiseAsRawBytes a => a -> Text
serialiseToRawBytesHexText Address ByronAddr
payaddr
          }
    Just (Left (AddressShelley Address ShelleyAddr
payaddr)) ->
      AddressInfo -> ExceptT AddressInfoError IO AddressInfo
forall a. a -> ExceptT AddressInfoError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (AddressInfo -> ExceptT AddressInfoError IO AddressInfo)
-> AddressInfo -> ExceptT AddressInfoError IO AddressInfo
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 = Address ShelleyAddr -> Text
forall a. SerialiseAsRawBytes a => a -> Text
serialiseToRawBytesHexText Address ShelleyAddr
payaddr
          }
    Just (Right StakeAddress
addr) ->
      AddressInfo -> ExceptT AddressInfoError IO AddressInfo
forall a. a -> ExceptT AddressInfoError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (AddressInfo -> ExceptT AddressInfoError IO AddressInfo)
-> AddressInfo -> ExceptT AddressInfoError IO AddressInfo
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 = StakeAddress -> Text
forall a. SerialiseAsRawBytes a => a -> Text
serialiseToRawBytesHexText StakeAddress
addr
          }

  case Maybe (File () 'Out)
mOutputFp of
    Just (File FilePath
fpath) -> IO () -> ExceptT AddressInfoError IO ()
forall a. IO a -> ExceptT AddressInfoError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ExceptT AddressInfoError IO ())
-> IO () -> ExceptT AddressInfoError IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> ByteString -> IO ()
LBS.writeFile FilePath
fpath (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ AddressInfo -> ByteString
forall a. ToJSON a => a -> ByteString
encodePretty AddressInfo
addrInfo
    Maybe (File () 'Out)
Nothing -> IO () -> ExceptT AddressInfoError IO ()
forall a. IO a -> ExceptT AddressInfoError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ExceptT AddressInfoError IO ())
-> IO () -> ExceptT AddressInfoError IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> IO ()
LBS.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ AddressInfo -> ByteString
forall a. ToJSON a => a -> ByteString
encodePretty AddressInfo
addrInfo