content: module HandleHumanLocalMUnitTests (handleHumanLocalMUnitTests) where
  
  import Prelude ()
  
  import Game.LambdaHack.Core.Prelude
  
  import qualified Data.EnumMap.Strict as EM
  import qualified Data.Text as T
  
  import Test.Tasty
  import Test.Tasty.HUnit
  
  import           Game.LambdaHack.Client.UI (SessionUI (..), modifySession)
  import           Game.LambdaHack.Client.UI.HandleHelperM
  import           Game.LambdaHack.Client.UI.HandleHumanLocalM
  import qualified Game.LambdaHack.Client.UI.HumanCmd as HumanCmd
  import           Game.LambdaHack.Client.UI.Msg
  import           Game.LambdaHack.Client.UI.MsgM
  import           Game.LambdaHack.Client.UI.TutorialHints
  import           Game.LambdaHack.Common.ActorState
  import           Game.LambdaHack.Common.Item
  import           Game.LambdaHack.Common.ItemAspect
  import           Game.LambdaHack.Common.Kind (emptyMultiGroupItem)
  import           Game.LambdaHack.Common.Level
  import           Game.LambdaHack.Common.Point
  import           Game.LambdaHack.Common.PointArray as PointArray
  import           Game.LambdaHack.Common.ReqFailure
  import           Game.LambdaHack.Common.State
  import           Game.LambdaHack.Content.TileKind
  import           Game.LambdaHack.Definition.DefsInternal
    (toContentId, toContentSymbol)
  
  import UnitTestHelpers
  
  testItemFull :: ItemFull
  testItemFull = ItemFull { itemBase = stubItem, itemKindId = toContentId 0, itemKind = emptyMultiGroupItem, itemDisco = ItemDiscoFull emptyAspectRecord, itemSuspect = False }
  
  handleHumanLocalMUnitTests :: TestTree
  handleHumanLocalMUnitTests = testGroup "handleHumanLocalMUnitTests"
    [ testCase "verify stubLevel has tile element" $
        case EM.lookup testLevelId (sdungeon stubState) of
          Nothing -> assertFailure "stubLevel lost in dungeon"
          Just level -> ltile level ! Point 0 0 @?= unknownId
    , testCase "verify stubCliState has actor" $
        getActorBody testActorId (cliState stubCliState) @?= testActor
    , testCase "permittedProjectClient stubCliState returns ProjectUnskilled" $ do
        let testFn = permittedProjectClient testActorId
        permittedProjectClientResultFnInMonad <- executorCli testFn stubCliState
        let ultimateResult =
              fst permittedProjectClientResultFnInMonad testItemFull
        ultimateResult @?= Left ProjectUnskilled
    , testCase "chooseItemProjectHuman" $ do
        let testFn = let triggerItems =
                           [ HumanCmd.TriggerItem {tiverb = "verb", tiobject = "object", tisymbols = [toContentSymbol 'a', toContentSymbol 'b']}
                           , HumanCmd.TriggerItem {tiverb = "verb2", tiobject = "object2", tisymbols = [toContentSymbol 'c']}
                           ]
                     in chooseItemProjectHuman testActorId triggerItems
        result <- executorCli testFn testCliStateWithItem
        showFailError (fromJust (fst result)) @?= "*aiming obstructed by terrain*"
    , testCase "tutorialHints-msg-in-history-report" $ do
        let testFn = do
              modifySession (\sess -> sess {scurTutorial = True})
                -- permit the client not to ignore tutorial hints
              tutorialHintMsgAdd CannotHarmYouInMelee
        result <- executorCli testFn testCliStateWithItem
        let maybeHistory = shistory <$> (cliSession . snd) result
        case maybeHistory of
          Nothing -> assertFailure "History is empty"
          Just history -> assertBool testFailureMsg isHintThere
           where
            renderedNewReports = reportToTexts . newReport $ history
            renderedHint = renderTutorialHints CannotHarmYouInMelee
            isHintThere = renderedHint `elem` renderedNewReports
            testFailureMsg = "Expected to find tutorial hint '"
              <> (T.unpack . renderTutorialHints $ CannotHarmYouInMelee)
              <> "' in SessionUI.shistory.newReport '"
              <> T.unpack (T.unlines renderedNewReports)
              <> "'"
    , testCase "psuitReq" $  do
        let testFn = psuitReq testActorId
        mpsuitReqMonad <- executorCli testFn testCliStateWithItem
        let mpsuitReq = fst mpsuitReqMonad
        case mpsuitReq of
          Left err -> do
            err @?= "aiming obstructed by terrain"
              -- TODO: I'd split the test into three tests, each taking a different branch and fail in the remaining two branches that the particular branch doesn't take. Here it takes the first branch, because unknown tiles are not walkable (regardless what I claimed previously) and so the player is surrounded by walls, basically, so aiming fails, because the projectiles wouldn't even leave the position of the actor. I think.
          Right psuitReqFun ->
            case psuitReqFun testItemFull of
              Left reqFail -> do
                reqFail @?= ProjectUnskilled
              Right (pos, _) -> do
                pos @?= Point 0 0
    , testCase "xhairLegalEps" $ do
        let testFn = xhairLegalEps testActorId
        result <- executorCli testFn testCliStateWithItem
        fst result @?= Right 114  -- not a coincidence this matches testFactionId,
                                  -- because @eps@ is initialized that way,
                                  -- for "randomness"
    ]
  