{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE ScopedTypeVariables        #-}

module Main (main) where

import           Deploy.Deploy
import           Deploy.Command
import           Deploy.HostSectionKey
import           Data.KeyStore
import           Data.KeyStore                  as KS
import qualified Data.ByteString.Char8          as B
import qualified Data.ByteString.Lazy.Char8     as LBS
import qualified Data.Text.IO                   as T
import           System.IO
import           Control.Applicative
import           Control.Exception


ks_fp, ks_mac_fp :: FilePath
ks_fp     = "deploy-keystore.json"
ks_mac_fp = "deploy-keystore.hash"

main :: IO ()
main =
 do CLI{..} <- parseCLI
    let cp0 = cli_params
        cp  = cp0 { cp_store = cp_store cp0 <|> Just ks_fp }
    case cli_command of
      Create       -> initialise cp no_keys
      ListHosts    -> mapM_ (putStrLn . encode) $ [minBound..maxBound :: HostID]
      SampleScript -> mapM_  sample_ln            [minBound..maxBound]
      KS args      -> KS.cli' (Just cp) args
      _            ->
         do ic <- instanceCtx cp
            let ic_ro = ic { ic_ctx_params = cp {cp_readonly = cp_readonly cp <|> Just True} }
            case cli_command of
              Sign -> return ()
              _    -> verify_ks True ic_ro
            case cli_command of
              Create                      -> error "main: Initialise"
              Rotate          mbh mbs mbk -> rotate  ic    $ key_prededicate mbh mbs mbk
              Deploy          mb hst      -> deploy  ic_ro hst                        >>= write mb
              Sign                        -> sign_ks ic_ro
              Verify                      -> T.putStrLn "the keystore matches the signature"
              ListHosts                   -> error "main: ListHosts"
              InfoKey         mbk         -> T.putStr $ keyHelp mbk
              InfoSection     mbs         -> sectionHelp mbs                          >>= T.putStr
              SecretScript                -> secretKeySummary ic sections             >>= T.putStr
              PublicScript                -> publicKeySummary ic sections ks_mac_fp   >>= T.putStr
              SampleScript                -> error "main: SampleScript"
              KS              _           -> error "main: KS"
            verify_ks False ic_ro

sign_ks :: IC -> IO ()
sign_ks ic = signKeystore ic sections >>= B.writeFile ks_mac_fp

verify_ks :: Bool -> IC -> IO ()
verify_ks fatal ic = chk =<< catch (B.readFile ks_mac_fp >>= verifyKeystore ic sections) hdl
  where
    chk True              = return ()
    chk False | fatal     = error msg
              | otherwise = hPutStrLn stderr msg

    hdl (se :: SomeException) =
                error $ "failure during keystore verification: " ++ show se

    msg = "the signature does not match the keystore"

no_keys :: KeyPredicate HostID SectionID KeyID
no_keys = noKeys

key_prededicate :: Maybe HostID -> Maybe SectionID -> Maybe KeyID -> KeyPredicate HostID SectionID KeyID
key_prededicate = keyPrededicate

sample_ln :: SectionID -> IO ()
sample_ln s = putStrLn $ "export " ++ "KEY_pw_" ++ s_ ++ "=pw_" ++ s_ ++ ";"
  where
    s_ = encode s

write :: Maybe FilePath -> LBS.ByteString -> IO ()
write = maybe LBS.putStrLn LBS.writeFile