{-# LANGUAGE ApplicativeDo   #-}
{-# LANGUAGE QuasiQuotes     #-}
{-# LANGUAGE RecordWildCards #-}

module KeygenOptions
       ( KeygenOptions (..)
       , KeygenCommand (..)
       , DumpAvvmSeedsOptions (..)
       , TestnetBalanceOptions (..)
       , FakeAvvmOptions (..)
       , GenKeysOptions (..)
       , getKeygenOptions
       ) where

import           Universum

import           Data.Version (showVersion)
import           Options.Applicative (Parser, auto, command, execParser,
                     fullDesc, header, help, helper, info, infoOption, long,
                     metavar, option, progDesc, short, strOption, subparser,
                     switch, value)

import           Pos.Chain.Genesis (FakeAvvmOptions (..),
                     TestnetBalanceOptions (..))
import           Pos.Client.CLI (configurationOptionsParser)
import           Pos.Launcher (ConfigurationOptions)

import           Paths_cardano_sl (version)

data KeygenOptions = KeygenOptions
    { koCommand              :: KeygenCommand
    , koConfigurationOptions :: ConfigurationOptions
    } deriving (Show)

data KeygenCommand
    = RearrangeMask FilePath
    | GenerateKey FilePath
    | GenerateVss FilePath
    | ReadKey FilePath
    | DumpAvvmSeeds DumpAvvmSeedsOptions
    | GenerateKeysBySpec GenKeysOptions
    | DumpGenesisData !FilePath !Bool
    deriving (Show)

data DumpAvvmSeedsOptions = DumpAvvmSeedsOptions
    { dasNumber :: Int
      -- ^ Number of seeds to generate.
    , dasPath   :: FilePath
      -- ^ Path to directory to generate seeds in.
    } deriving (Show)

data GenKeysOptions = GenKeysOptions
    { gkoOutDir     :: FilePath
    , gkoKeyPattern :: FilePath
    } deriving (Show)

keygenCommandParser :: Parser KeygenCommand
keygenCommandParser =
    subparser $ mconcat $
    [ command "rearrange"
      (infoH rearrangeMask (progDesc "Rearrange keyfiles."))
    , command "generate-key"
      (infoH generateKey (progDesc "Generate keyfile."))
    , command "generate-vss"
      (infoH generateVss (progDesc "Generate VSS certificate."))
    , command "read-key"
      (infoH readKey (progDesc "Dump keyfile contents."))
    , command "generate-avvm-seeds"
      (infoH (fmap DumpAvvmSeeds dumpAvvmSeedsParser)
            (progDesc "Generate avvm seeds with public keys."))
    , command "generate-keys-by-spec"
      (infoH (GenerateKeysBySpec <$> keysBySpecParser)
            (progDesc "Generate secret keys and avvm seed by genesis-spec.yaml"))
    , command "dump-genesis-data"
      (infoH dumpGenesisDataParser
            (progDesc "Dump genesis data (as per configuration) in json format"))
    ]
  where
    infoH a b = info (helper <*> a) b
    rearrangeMask = fmap RearrangeMask . strOption $
        long    "mask" <>
        metavar "PATTERN" <>
        help    "Secret keyfiles to rearrange."
    generateKey = fmap GenerateKey . strOption $
        long    "path" <>
        metavar "PATH" <>
        help    "Write the key to this path"
    generateVss = fmap GenerateVss . strOption $
        long    "path" <>
        metavar "PATH" <>
        help    "Generate a VSS certificate for this key"
    readKey = fmap ReadKey . strOption $
        long "path" <>
        metavar "PATH" <>
        help "Dump the contents of this keyfile"
    dumpGenesisDataParser = do
        dgdPath <- strOption $
            long "path" <>
            metavar "PATH" <>
            value "genesis-data.json" <>
            help "Path to file where genesis data should be dumped"
        dgdCanonical <- switch $
            long "canonical" <>
            help "Whether genesis data should be in canonical json"
        pure $ DumpGenesisData dgdPath dgdCanonical

dumpAvvmSeedsParser :: Parser DumpAvvmSeedsOptions
dumpAvvmSeedsParser = do
    dasNumber <-
        option auto $
        long "count" <> short 'n' <> metavar "INTEGER" <>
        help "Number of seeds to generate."
    dasPath <-
        strOption $
        long "output" <> short 'o' <> metavar "FILEPATH" <>
        help "Path to dump generated seeds to."
    pure $ DumpAvvmSeedsOptions {..}

keysBySpecParser  :: Parser GenKeysOptions
keysBySpecParser = do
    gkoOutDir <- strOption $
        long    "genesis-out-dir" <>
        metavar "DIR" <>
        value   "." <>
        help    "Directory to dump keys and avvm seeds into."
    gkoKeyPattern <- strOption $
        long    "file-pattern" <>
        metavar "PATTERN" <>
        value   "key{}.sk" <>
        help    "Filename pattern for generated keyfiles \
                \(`{}` is a place for number). E.g. key{}.sk"
    pure $ GenKeysOptions {..}

getKeygenOptions :: IO KeygenOptions
getKeygenOptions = execParser programInfo
  where
    programInfo = info (helper <*> versionOption <*> koParser) $
        fullDesc <> header "Tool to generate keyfiles-related data."

    versionOption = infoOption
        ("cardano-keygen-" <> showVersion version)
        (long "version" <> help "Show version.")

    koParser = KeygenOptions <$> keygenCommandParser <*> configurationOptionsParser
