content: {-# OPTIONS_GHC -Wno-missing-signatures #-}
  {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  {-# LANGUAGE DeriveGeneric #-}
  
  module Types
    (  -- * Atomic types
      OS(..)
    , Cluster(..)
    , Backend(..)
    , Config(..), configFilename
    , ConfigRequest(..)
    , SigningResult(..)
  
    , AppName(..)
    , BuildJob(..)
    , Version(..)
  
    -- * Flags
    , TestInstaller(..), testInstaller
  
    -- * Misc
    , lshowText
    , tt
    , packageFileName
    , getAppVersion
    , packageVersion
    , clusterNetwork
    , withDir
    , InstallerConfig(..)
    )
  where
  
  import           Universum                    hiding (FilePath)
  import qualified Data.Text                        as T
  import           Filesystem.Path
  import           Filesystem.Path.CurrentOS           (fromText, encodeString)
  import           Turtle                              (pwd, cd)
  import           Turtle.Format                       (format, fp)
  import           Data.Aeson                          (FromJSON(..), withObject, eitherDecode, (.:), genericParseJSON, defaultOptions)
  import qualified Data.ByteString.Lazy.Char8       as L8
  
  data OS
    = Linux64
    | Win64
    deriving (Bounded, Enum, Eq, Read, Show)
  
  data Cluster
    = Selfnode
    | Mainnet
    | Mainnet_Flight
    | Staging
    | Shelley_QA
    | Testnet
    | Alonzo_Purple
    | Vasil_Dev
    | Preprod
    | Preview
    deriving (Bounded, Enum, Eq, Read, Show)
  
  -- | The wallet backend to include in the installer.
  --
  data Backend
    = Cardano FilePath -- ^ Cardano SL with the given daedalus-bridge.
    deriving (Eq, Show)
  
  data SigningResult
    = SignedOK
    | NotSigned
    deriving (Bounded, Enum, Eq, Read, Show)
  
  data Config
    = Launcher
    deriving (Bounded, Enum, Eq, Show)
  
  configFilename :: Config -> FilePath
  configFilename Launcher = "launcher-config.yaml"
  
  -- | What runtime config file to generate.
  data ConfigRequest = ConfigRequest
    { rOS      :: OS
    , rCluster :: Cluster
    , rConfig  :: Config
    } deriving (Eq, Show)
  
  newtype AppName      = AppName      { fromAppName      :: Text } deriving (Eq, IsString, Show)
  newtype BuildJob     = BuildJob     { fromBuildJob     :: Text } deriving (Eq, IsString, Show)
  newtype Version      = Version      { fromVer          :: Text } deriving (Eq, IsString, Show)
  
  data TestInstaller      = DontTestInstaller         | TestInstaller          deriving (Eq, Show)
  testInstaller    True   =                             TestInstaller
  testInstaller    False  = DontTestInstaller
  
  lshowText :: Show a => a -> Text
  lshowText = T.toLower . Universum.show
  
  tt :: FilePath -> Text
  tt = format fp
  
  -- | Value of the NETWORK variable used by the npm build.
  -- See also: the cluster argument in default.nix.
  clusterNetwork :: Cluster -> Text
  clusterNetwork Selfnode = "selfnode"
  clusterNetwork Mainnet = "mainnet"
  clusterNetwork Mainnet_Flight = "mainnet_flight"
  clusterNetwork Staging = "staging"
  clusterNetwork Shelley_QA = "shelley_qa"
  clusterNetwork Testnet = "testnet"
  clusterNetwork Alonzo_Purple = "alonzo_purple"
  clusterNetwork Vasil_Dev = "vasil_dev"
  clusterNetwork Preprod = "preprod"
  clusterNetwork Preview = "preview"
  
  packageFileName :: Text -> OS -> Cluster -> Version -> Backend -> Maybe BuildJob -> Maybe BuildJob -> FilePath
  packageFileName uglyName _os cluster ver backend buildJob buildCounter = fromText name <.> ext
    where
      name = T.intercalate "-" parts
      parts = [uglyName, fromVer ver <> buildCounter', lshowText cluster] ++ buildJob' ++ [archOS]
      _backend' = case backend of
                   Cardano _ -> "cardano-wallet"
      ext = case _os of
              Win64   -> "exe"
              Linux64 -> "bin"
      _os' = case _os of
              Win64   -> "windows"
              Linux64 -> "linux"
      archOS = case _os of
              Win64   -> "x86_64-windows"
              Linux64 -> "x86_64-linux"
      buildJob' = maybe [] (\b -> [fromBuildJob b]) buildJob
      buildCounter' = "-" <> maybe "0" fromBuildJob buildCounter
  
  instance FromJSON Version where
    parseJSON = withObject "Package" $ \o -> Version <$> o .: "version"
  
  getAppVersion :: FilePath -> IO Version
  getAppVersion packageJSON = L8.readFile (encodeString packageJSON) >>= packageVersion
  
  packageVersion :: L8.ByteString -> IO Version
  packageVersion json = case eitherDecode json of
    Right ver -> pure ver
    Left err -> fail err
  
  -- | More or less the same as pushd function in newer Turtle
  withDir :: FilePath -> IO a -> IO a
  withDir path = bracket (pwd >>= \old -> (cd path >> pure old)) cd . const
  
  data InstallerConfig = InstallerConfig {
        installDirectory :: Text
      , spacedName :: Text -- ^ ‘Daedalus Testnet’, etc.
      , uglyName :: Text -- ^ `daedalus` or `lace-desktop`, etc.
      , macPackageName :: Text
      , dataDir :: Text
      , configPath :: Maybe Text
      } deriving (Generic, Show)
  
  instance FromJSON InstallerConfig where
    parseJSON = genericParseJSON defaultOptions
  