{-# LANGUAGE NoImplicitPrelude     #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedRecordDot   #-}

-- | Build configuration
module Stack.Config.Build
 ( buildOptsFromMonoid
 , haddockOptsFromMonoid
 , testOptsFromMonoid
 , benchmarkOptsFromMonoid
 ) where

import           Distribution.Verbosity ( normal )
import           Stack.BuildOpts
                   ( defaultBenchmarkOpts, defaultHaddockOpts, defaultTestOpts )
import           Stack.Prelude
import           Stack.Types.BuildOpts
                   ( BenchmarkOpts (..), BuildOpts (..), HaddockOpts (..)
                   , TestOpts (..)
                   )
import qualified Stack.Types.BuildOpts as BenchmarkOpts ( BenchmarkOpts (..) )
import qualified Stack.Types.BuildOpts as HaddockOpts ( HaddockOpts (..) )
import qualified Stack.Types.BuildOpts as TestOpts ( TestOpts (..) )
import           Stack.Types.BuildOptsMonoid
                   ( BenchmarkOptsMonoid (..), BuildOptsMonoid (..)
                   , CabalVerbosity (..), HaddockOptsMonoid (..)
                   , ProgressBarFormat (..), TestOptsMonoid (..)
                   )

-- | Interprets BuildOptsMonoid options.
buildOptsFromMonoid :: BuildOptsMonoid -> BuildOpts
buildOptsFromMonoid buildMonoid = BuildOpts
  { libProfile = fromFirstFalse
      (  buildMonoid.libProfile
      <> FirstFalse (if tracing || profiling then Just True else Nothing)
      )
  , exeProfile = fromFirstFalse
      (  buildMonoid.exeProfile
      <> FirstFalse (if tracing || profiling then Just True else Nothing)
      )
  , libStrip = fromFirstTrue
      (  buildMonoid.libStrip
      <> FirstTrue (if noStripping then Just False else Nothing)
      )
  , exeStrip = fromFirstTrue
      (  buildMonoid.exeStrip
      <> FirstTrue (if noStripping then Just False else Nothing)
      )
  , buildHaddocks = fromFirstFalse buildMonoid.buildHaddocks
  , haddockOpts = haddockOptsFromMonoid buildMonoid.haddockOpts
  , openHaddocks =
         not isHaddockFromHackage
      && fromFirstFalse buildMonoid.openHaddocks
  , haddockDeps = if isHaddockFromHackage
      then Nothing
      else getFirst buildMonoid.haddockDeps
  , haddockExecutables =
         not isHaddockFromHackage
      && fromFirstFalse buildMonoid.haddockExecutables
  , haddockTests =
         not isHaddockFromHackage
      && fromFirstFalse buildMonoid.haddockTests
  , haddockBenchmarks =
         not isHaddockFromHackage
      && fromFirstFalse buildMonoid.haddockBenchmarks
  , haddockInternal =
         not isHaddockFromHackage
      && fromFirstFalse buildMonoid.haddockInternal
  , haddockHyperlinkSource =
         isHaddockFromHackage
      || fromFirstTrue buildMonoid.haddockHyperlinkSource
  , haddockForHackage = isHaddockFromHackage
  , installExes = fromFirstFalse buildMonoid.installExes
  , installCompilerTool = fromFirstFalse buildMonoid.installCompilerTool
  , preFetch = fromFirstFalse buildMonoid.preFetch
  , keepGoing = getFirst buildMonoid.keepGoing
  , keepTmpFiles = fromFirstFalse buildMonoid.keepTmpFiles
  , forceDirty = isHaddockFromHackage || fromFirstFalse buildMonoid.forceDirty
  , tests = fromFirstFalse buildMonoid.tests
  , testOpts = testOptsFromMonoid buildMonoid.testOpts additionalArgs
  , benchmarks = fromFirstFalse buildMonoid.benchmarks
  , benchmarkOpts =
      benchmarkOptsFromMonoid buildMonoid.benchmarkOpts additionalArgs
  , reconfigure = fromFirstFalse buildMonoid.reconfigure
  , cabalVerbose = fromFirst (CabalVerbosity normal) buildMonoid.cabalVerbose
  , splitObjs = fromFirstFalse buildMonoid.splitObjs
  , skipComponents = buildMonoid.skipComponents
  , interleavedOutput = fromFirstTrue buildMonoid.interleavedOutput
  , progressBar = fromFirst CappedBar buildMonoid.progressBar
  , ddumpDir = getFirst buildMonoid.ddumpDir
  }
 where
  isHaddockFromHackage = fromFirstFalse buildMonoid.haddockForHackage
  -- These options are not directly used in bopts, instead they
  -- transform other options.
  tracing = getAny buildMonoid.trace
  profiling = getAny buildMonoid.profile
  noStripping = getAny buildMonoid.noStrip
  -- Additional args for tracing / profiling
  additionalArgs =
    if tracing || profiling
      then Just $ "+RTS" : catMaybes [trac, prof, Just "-RTS"]
      else Nothing
  trac =
    if tracing
      then Just "-xc"
      else Nothing
  prof =
    if profiling
      then Just "-p"
      else Nothing

-- | Interprets HaddockOptsMonoid options.
haddockOptsFromMonoid :: HaddockOptsMonoid -> HaddockOpts
haddockOptsFromMonoid hoMonoid = defaultHaddockOpts
  { HaddockOpts.additionalArgs = hoMonoid.additionalArgs }

-- | Interprets TestOptsMonoid options.
testOptsFromMonoid :: TestOptsMonoid -> Maybe [String] -> TestOpts
testOptsFromMonoid toMonoid madditional = defaultTestOpts
  { TestOpts.rerunTests = fromFirstTrue toMonoid.rerunTests
  , TestOpts.additionalArgs =
      fromMaybe [] madditional <> toMonoid.additionalArgs
  , TestOpts.coverage = fromFirstFalse toMonoid.coverage
  , TestOpts.runTests = fromFirstTrue toMonoid.runTests
  , TestOpts.maximumTimeSeconds =
      fromFirst
        defaultTestOpts.maximumTimeSeconds
        toMonoid.maximumTimeSeconds
  , TestOpts.allowStdin = fromFirstTrue toMonoid.allowStdin
  }

-- | Interprets BenchmarkOptsMonoid options.
benchmarkOptsFromMonoid ::
     BenchmarkOptsMonoid
  -> Maybe [String]
  -> BenchmarkOpts
benchmarkOptsFromMonoid beoMonoid madditional = defaultBenchmarkOpts
  { BenchmarkOpts.additionalArgs =
      fmap (\args -> unwords args <> " ") madditional <>
      getFirst beoMonoid.additionalArgs
  , BenchmarkOpts.runBenchmarks = fromFirstTrue beoMonoid.runBenchmarks
  }
