{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}

-- | This module defines constants derived from the environment.
module Cardano.CLI.Environment
  ( EnvCli (..)
  , envCliAnyEon
  , getEnvCli
  , getEnvNetworkId
  , getEnvSocketPath
  )
where

import           Cardano.Api (AnyCardanoEra (..), CardanoEra (..), Eon, EraInEon (..),
                   NetworkId (..), NetworkMagic (..), forEraInEonMaybe)

import           Data.Typeable
import           Data.Word (Word32)
import qualified System.Environment as IO
import qualified System.IO as IO
import           Text.Read (readMaybe)

data EnvCli = EnvCli
  { EnvCli -> Maybe NetworkId
envCliNetworkId :: Maybe NetworkId
  , EnvCli -> Maybe String
envCliSocketPath :: Maybe FilePath
  , EnvCli -> Maybe AnyCardanoEra
envCliAnyCardanoEra :: Maybe AnyCardanoEra
  }

getEnvCli :: IO EnvCli
getEnvCli :: IO EnvCli
getEnvCli = do
  Maybe NetworkId
mNetworkId <- IO (Maybe NetworkId)
getEnvNetworkId
  Maybe String
mSocketPath <- IO (Maybe String)
getEnvSocketPath
  Maybe AnyCardanoEra
mCardanoEra <- IO (Maybe AnyCardanoEra)
getCardanoEra

  EnvCli -> IO EnvCli
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    EnvCli
      { envCliNetworkId :: Maybe NetworkId
envCliNetworkId = Maybe NetworkId
mNetworkId
      , envCliSocketPath :: Maybe String
envCliSocketPath = Maybe String
mSocketPath
      , envCliAnyCardanoEra :: Maybe AnyCardanoEra
envCliAnyCardanoEra = Maybe AnyCardanoEra
mCardanoEra
      }

envCliAnyEon :: Typeable eon => Eon eon => EnvCli -> Maybe (EraInEon eon)
envCliAnyEon :: forall (eon :: * -> *).
(Typeable eon, Eon eon) =>
EnvCli -> Maybe (EraInEon eon)
envCliAnyEon EnvCli
envCli = do
  AnyCardanoEra CardanoEra era
era <- EnvCli -> Maybe AnyCardanoEra
envCliAnyCardanoEra EnvCli
envCli
  CardanoEra era -> (eon era -> EraInEon eon) -> Maybe (EraInEon eon)
forall (eon :: * -> *) era a.
Eon eon =>
CardanoEra era -> (eon era -> a) -> Maybe a
forEraInEonMaybe CardanoEra era
era eon era -> EraInEon eon
forall era (eon :: * -> *).
(Typeable era, Typeable (eon era), Eon eon) =>
eon era -> EraInEon eon
EraInEon

-- | If the environment variable @CARDANO_NODE_NETWORK_ID@ is set, then return the network id therein.
-- Otherwise, return 'Nothing'.
getEnvNetworkId :: IO (Maybe NetworkId)
getEnvNetworkId :: IO (Maybe NetworkId)
getEnvNetworkId = do
  Maybe String
mNetworkIdString <- String -> IO (Maybe String)
IO.lookupEnv String
"CARDANO_NODE_NETWORK_ID"

  case Maybe String
mNetworkIdString of
    Maybe String
Nothing -> Maybe NetworkId -> IO (Maybe NetworkId)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe NetworkId
forall a. Maybe a
Nothing
    Just String
networkIdString -> do
      case String
networkIdString of
        String
"mainnet" -> Maybe NetworkId -> IO (Maybe NetworkId)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe NetworkId -> IO (Maybe NetworkId))
-> Maybe NetworkId -> IO (Maybe NetworkId)
forall a b. (a -> b) -> a -> b
$ NetworkId -> Maybe NetworkId
forall a. a -> Maybe a
Just NetworkId
Mainnet
        String
_ ->
          case forall a. Read a => String -> Maybe a
readMaybe @Word32 String
networkIdString of
            Just Word32
networkId -> Maybe NetworkId -> IO (Maybe NetworkId)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe NetworkId -> IO (Maybe NetworkId))
-> Maybe NetworkId -> IO (Maybe NetworkId)
forall a b. (a -> b) -> a -> b
$ NetworkId -> Maybe NetworkId
forall a. a -> Maybe a
Just (NetworkId -> Maybe NetworkId) -> NetworkId -> Maybe NetworkId
forall a b. (a -> b) -> a -> b
$ NetworkMagic -> NetworkId
Testnet (NetworkMagic -> NetworkId) -> NetworkMagic -> NetworkId
forall a b. (a -> b) -> a -> b
$ Word32 -> NetworkMagic
NetworkMagic Word32
networkId
            Maybe Word32
Nothing -> do
              Handle -> String -> IO ()
IO.hPutStrLn Handle
IO.stderr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
                [String] -> String
forall a. Monoid a => [a] -> a
mconcat
                  [ String
"The network id specified in CARDANO_NODE_NETWORK_ID invalid: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
networkIdString
                  , String
" It should be either 'mainnet' or a number."
                  ]
              Maybe NetworkId -> IO (Maybe NetworkId)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe NetworkId
forall a. Maybe a
Nothing

-- | If the environment variable @CARDANO_NODE_SOCKET_PATH@ is set, then return the set value.
-- Otherwise, return 'Nothing'.
getEnvSocketPath :: IO (Maybe FilePath)
getEnvSocketPath :: IO (Maybe String)
getEnvSocketPath = String -> IO (Maybe String)
IO.lookupEnv String
"CARDANO_NODE_SOCKET_PATH"

-- | If the environment variable @CARDANO_ERA@ is set, then return the set value.
-- Otherwise, return 'Nothing'.
getCardanoEra :: IO (Maybe AnyCardanoEra)
getCardanoEra :: IO (Maybe AnyCardanoEra)
getCardanoEra = do
  Maybe String
mEraString <- String -> IO (Maybe String)
IO.lookupEnv String
"CARDANO_ERA"

  case Maybe String
mEraString of
    Just String
eraString ->
      case String
eraString of
        String
"byron" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra ByronEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra ByronEra
ByronEra
        String
"shelley" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra ShelleyEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra ShelleyEra
ShelleyEra
        String
"allegra" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra AllegraEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra AllegraEra
AllegraEra
        String
"mary" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra MaryEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra MaryEra
MaryEra
        String
"alonzo" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra AlonzoEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra AlonzoEra
AlonzoEra
        String
"babbage" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra BabbageEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra BabbageEra
BabbageEra
        String
"conway" -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra))
-> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ AnyCardanoEra -> Maybe AnyCardanoEra
forall a. a -> Maybe a
Just (AnyCardanoEra -> Maybe AnyCardanoEra)
-> AnyCardanoEra -> Maybe AnyCardanoEra
forall a b. (a -> b) -> a -> b
$ CardanoEra ConwayEra -> AnyCardanoEra
forall era. Typeable era => CardanoEra era -> AnyCardanoEra
AnyCardanoEra CardanoEra ConwayEra
ConwayEra
        String
unknown -> String -> IO (Maybe AnyCardanoEra)
forall a. HasCallStack => String -> a
error (String -> IO (Maybe AnyCardanoEra))
-> String -> IO (Maybe AnyCardanoEra)
forall a b. (a -> b) -> a -> b
$ String
"Unknown era: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
unknown -- TODO improve error handling
    Maybe String
Nothing -> Maybe AnyCardanoEra -> IO (Maybe AnyCardanoEra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe AnyCardanoEra
forall a. Maybe a
Nothing