module Stackctl.Spec.Changes
  ( ChangesOptions(..)
  , runChangesOptions
  , runChanges
  ) where

import Stackctl.Prelude

import Blammo.Logging.Logger (pushLoggerLn)
import qualified Data.Text.IO as T
import Options.Applicative
import Stackctl.AWS hiding (action)
import Stackctl.AWS.Scope
import Stackctl.Colors
import Stackctl.DirectoryOption (HasDirectoryOption)
import Stackctl.FilterOption (HasFilterOption)
import Stackctl.ParameterOption
import Stackctl.Spec.Changes.Format
import Stackctl.Spec.Discover
import Stackctl.StackSpec
import Stackctl.StackSpecPath

data ChangesOptions = ChangesOptions
  { scoFormat :: Format
  , scoParameters :: [Parameter]
  , scoOutput :: Maybe FilePath
  }

-- brittany-disable-next-binding

runChangesOptions :: Parser ChangesOptions
runChangesOptions = ChangesOptions
  <$> formatOption
  <*> many parameterOption
  <*> optional (argument str
    (  metavar "PATH"
    <> help "Write changes summary to PATH"
    <> action "file"
    ))

runChanges
  :: ( MonadMask m
     , MonadUnliftIO m
     , MonadResource m
     , MonadLogger m
     , MonadReader env m
     , HasLogger env
     , HasAwsScope env
     , HasAwsEnv env
     , HasDirectoryOption env
     , HasFilterOption env
     )
  => ChangesOptions
  -> m ()
runChanges ChangesOptions {..} = do
  -- Clear file before starting, as we have to use append for each spec
  liftIO $ traverse_ (`T.writeFile` "") scoOutput

  specs <- discoverSpecs

  for_ specs $ \spec -> do
    withThreadContext ["stackName" .= stackSpecStackName spec] $ do
      emChangeSet <- createChangeSet spec scoParameters

      case emChangeSet of
        Left err -> do
          logError $ "Error creating ChangeSet" :# ["error" .= err]
          exitFailure
        Right mChangeSet -> do
          colors <- case scoOutput of
            Nothing -> getColorsLogger
            Just{} -> pure noColors

          let
            name = pack $ stackSpecPathFilePath $ stackSpecSpecPath spec
            formatted = formatChangeSet colors name scoFormat mChangeSet

          case scoOutput of
            Nothing -> pushLoggerLn formatted
            Just p -> liftIO $ T.appendFile p $ formatted <> "\n"
