content: module Test.Iris.Cli (cliSpec, cliSpecParserConflicts) where
  
  import Options.Applicative (getParseResult)
  import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldBe, shouldReturn)
  
  import Iris (CliEnvSettings (..))
  import Iris.Cli (VersionSettings (versionSettingsMkDesc))
  import Iris.Cli.Colour (ColourOption (..))
  import Iris.Cli.Interactive (InteractiveMode (..), handleInteractiveMode)
  import Iris.Cli.Internal
  import Iris.Cli.ParserInfo (cmdParserInfo)
  import Iris.Cli.Version (defaultVersionSettings)
  import Iris.Settings (defaultCliEnvSettings)
  
  import Test.Iris.Common (checkCI)
  
  import qualified Options.Applicative as Opt
  import qualified Paths_iris as Autogen
  
  expectedHelpText :: String
  expectedHelpText =
      "Simple CLI program\n\
      \\n\
      \Usage: <iris-test> [--no-input] [--colour | --no-colour]\n\
      \\n\
      \  CLI tool build with iris - a Haskell CLI framework\n\
      \\n\
      \Available options:\n\
      \  -h,--help                Show this help text\n\
      \  --no-input               Enter the terminal in non-interactive mode\n\
      \  --colour                 Always output colours\n\
      \  --no-colour              Never output colours"
  
  expectedHelpTextWithVersion :: String
  expectedHelpTextWithVersion =
      "Simple CLI program\n\
      \\n\
      \Usage: <iris-test> [--version] [--numeric-version] [--no-input] \n\
      \                   [--colour | --no-colour]\n\
      \\n\
      \  CLI tool build with iris - a Haskell CLI framework\n\
      \\n\
      \Available options:\n\
      \  -h,--help                Show this help text\n\
      \  --version                Show application version\n\
      \  --numeric-version        Show only numeric application version\n\
      \  --no-input               Enter the terminal in non-interactive mode\n\
      \  --colour                 Always output colours\n\
      \  --no-colour              Never output colours"
  
  expectedNumericVersion :: String
  expectedNumericVersion = "0.1.0.0"
  
  cliSpec :: Spec
  cliSpec = describe "Cli Options" $ do
      let parserPrefs = Opt.defaultPrefs
      it "help without version environment" $ do
          let parserInfo = cmdParserInfo defaultCliEnvSettings
          let result = Opt.execParserPure parserPrefs parserInfo ["--help"]
          parseResultHandlerFailure result expectedHelpText
      it "help with version environment" $ do
          let cliEnvSettings = defaultCliEnvSettings{cliEnvSettingsVersionSettings = Just (defaultVersionSettings Autogen.version)}
          let parserInfo = cmdParserInfo cliEnvSettings
          let result = Opt.execParserPure parserPrefs parserInfo ["--help"]
          parseResultHandlerFailure result expectedHelpTextWithVersion
      it "--numeric-version returns correct version" $ do
          let cliEnvSettings = defaultCliEnvSettings{cliEnvSettingsVersionSettings = Just (defaultVersionSettings Autogen.version)}
          let parserInfo = cmdParserInfo cliEnvSettings
          let result = Opt.execParserPure parserPrefs parserInfo ["--numeric-version"]
          parseResultHandlerFailure result expectedNumericVersion
      it "CI interactivity check" $ do
          handleInteractiveMode NonInteractive `shouldReturn` NonInteractive
          isCi <- checkCI
          if isCi
              then handleInteractiveMode Interactive `shouldReturn` NonInteractive
              else handleInteractiveMode Interactive `shouldReturn` Interactive
      it "Handles colour mode" $ do
          let parserInfo = cmdParserInfo defaultCliEnvSettings
          let coloption args = getParseResult $ cmdColourOption <$> Opt.execParserPure parserPrefs parserInfo args
          coloption ["--colour"] `shouldBe` pure Always
          coloption ["--no-colour"] `shouldBe` pure Never
          coloption [] `shouldBe` pure Auto
  
      it "--version returns correct version text" $ do
          let expectedVersionMkDescription = ("Version " ++)
          let cliEnvSettings = defaultCliEnvSettings{cliEnvSettingsVersionSettings = Just $ (defaultVersionSettings Autogen.version){versionSettingsMkDesc = expectedVersionMkDescription}}
          let parserInfo = cmdParserInfo cliEnvSettings
          let expectedVersion = expectedVersionMkDescription expectedNumericVersion
          let result = Opt.execParserPure parserPrefs parserInfo ["--version"]
          parseResultHandlerFailure result expectedVersion
  
  newtype UserDefinedParser a = UserDefinedParser {noInteractive :: a}
  
  userDefinedNoInputOption :: Opt.Parser (UserDefinedParser String)
  userDefinedNoInputOption =
      UserDefinedParser
          <$> Opt.strOption (Opt.long "no-input")
  
  userDefinedNoInputSwitch :: Opt.Parser (UserDefinedParser Bool)
  userDefinedNoInputSwitch =
      UserDefinedParser
          <$> Opt.switch (Opt.long "no-input")
  
  userDefinedNoInputOnCommand :: Opt.Parser (UserDefinedParser Bool)
  userDefinedNoInputOnCommand =
      Opt.subparser
          ( Opt.command
              "test-command"
              (Opt.info userDefinedNoInputSwitch Opt.fullDesc)
          )
  
  customParserSettings :: Opt.Parser (UserDefinedParser a) -> CliEnvSettings (UserDefinedParser a) ()
  customParserSettings parser =
      CliEnvSettings
          { cliEnvSettingsCmdParser = parser
          , cliEnvSettingsAppEnv = ()
          , cliEnvSettingsHeaderDesc = "Simple CLI program"
          , cliEnvSettingsProgDesc = "CLI tool build with iris - a Haskell CLI framework"
          , cliEnvSettingsVersionSettings = Nothing
          , cliEnvSettingsAppName = Nothing
          }
  
  argValue :: String
  argValue = "someValue"
  
  expectedErrorTextUserDefinedNoInputArg :: String
  expectedErrorTextUserDefinedNoInputArg =
      "Invalid argument `"
          <> argValue
          <> "'\n\
             \\n\
             \Usage: <iris-test> [--no-input] --no-input ARG [--colour | --no-colour]\n\
             \\n\
             \  CLI tool build with iris - a Haskell CLI framework"
  
  expectedErrorTextUserDefinedNoInputNoArg :: String
  expectedErrorTextUserDefinedNoInputNoArg =
      "Missing: --no-input ARG\n\
      \\n\
      \Usage: <iris-test> [--no-input] --no-input ARG [--colour | --no-colour]\n\
      \\n\
      \  CLI tool build with iris - a Haskell CLI framework"
  
  cliSpecParserConflicts :: Spec
  cliSpecParserConflicts = describe "Cli Parser Conflicts" $ do
      let parserPrefs = Opt.defaultPrefs
      it "--no-input=someValue defined by user - arg provided" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOption
          let result = Opt.execParserPure parserPrefs parserInfo ["--no-input", argValue]
          parseResultHandlerFailure result expectedErrorTextUserDefinedNoInputArg
      it "--no-input=someValue defined by user - no arg provided" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOption
          let result = Opt.execParserPure parserPrefs parserInfo ["--no-input"]
          parseResultHandlerFailure result expectedErrorTextUserDefinedNoInputNoArg
      it "--no-input=someValue defined by user - not provided at all" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOption
          let result = Opt.execParserPure parserPrefs parserInfo []
          parseResultHandlerFailure result expectedErrorTextUserDefinedNoInputNoArg
      it "--no-input switch defined by user - provided" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputSwitch
          let result = Opt.execParserPure parserPrefs parserInfo ["--no-input"]
          parseResultHandlerSuccess result ["NonInteractive", "False"]
      it "--no-input switch defined by user - not provided" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputSwitch
          let result = Opt.execParserPure parserPrefs parserInfo []
          parseResultHandlerSuccess result ["Interactive", "False"]
      it "--no-input switch with command defined by user - user provided" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOnCommand
          let result = Opt.execParserPure parserPrefs parserInfo ["test-command", "--no-input"]
          parseResultHandlerSuccess result ["Interactive", "True"]
      it "--no-input switch with command defined by user - internal provided" $ do
          let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOnCommand
          let result = Opt.execParserPure parserPrefs parserInfo ["--no-input", "test-command"]
          parseResultHandlerSuccess result ["NonInteractive", "False"]
  
  parseResultHandlerSuccess :: Show b => Opt.ParserResult (Cmd (UserDefinedParser b)) -> [String] -> Expectation
  parseResultHandlerSuccess parseResult expected =
      case parseResult of
          Opt.Failure _ -> expectationFailure "Expected 'Success' but got 'Failure' "
          Opt.Success a -> do
              let internalNoInput = show $ cmdInteractiveMode a
              let userDefinedNoInput = show . noInteractive . cmdCmd $ a
              shouldBe [internalNoInput, userDefinedNoInput] expected
          Opt.CompletionInvoked completionResult -> expectationFailure $ "Expected 'Success' but got: " <> show completionResult
  
  parseResultHandlerFailure :: Opt.ParserResult a -> String -> Expectation
  parseResultHandlerFailure parseResult expected =
      case parseResult of
          -- The help functionality is baked into optparse-applicative and presents itself as a ParserFailure.
          Opt.Failure (Opt.ParserFailure getFailure) -> do
              let (helpText, _exitCode, _int) = getFailure "<iris-test>"
              show helpText `shouldBe` expected
          Opt.Success _ -> expectationFailure "Expected 'Failure' but got 'Success' "
          Opt.CompletionInvoked completionResult -> expectationFailure $ "Expected 'Failure' but got: " <> show completionResult
  