{-# 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 System.Environment qualified as IO
import System.IO qualified 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