content: {-# LANGUAGE BangPatterns #-}
  {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE RecursiveDo #-}
  
  module Main where
  
  import Control.Monad.Fix
  import Data.Maybe
  import qualified Data.Map as Map
  
  import Reflex
  import Reflex.EventWriter.Base
  import Reflex.Network
  import Reflex.Patch.MapWithMove
  import Test.Run
  
  main :: IO ()
  main = do
    let actions =  [ Increment, Update0th, Increment, Swap, Increment, Increment ]
    os <- runAppB testPatchMapWithMove $ map Just actions
    -- If the final counter value in the adjusted widgets corresponds to the number of times it has
    -- been incremented, we know that the networks haven't broken.
    let expectedCount = length $ ffilter (== Increment) actions
    -- let !True = last (last os) == [expectedCount,expectedCount] -- TODO re-enable this test after issue #369 has been resolved
    return ()
  
  data PatchMapTestAction
    = Increment
    | Swap
    | Update0th
    deriving Eq
  
  -- See https://github.com/reflex-frp/reflex/issues/369 for the bug that this is testing.
  testPatchMapWithMove
    :: forall t m
    .  ( Reflex t
       , Adjustable t m
       , MonadHold t m
       , MonadFix m
       )
    => Event t PatchMapTestAction
    -> m (Behavior t [Int])
  testPatchMapWithMove pulse = do
    let pulseAction = ffor pulse $ \case
          Increment -> Nothing
          Swap -> patchMapWithMove $ Map.fromList
            [ (0, NodeInfo (From_Move 1) (Just 1))
            , (1, NodeInfo (From_Move 0) (Just 0))
            ]
          Update0th -> patchMapWithMove $ Map.fromList
            [ (0, NodeInfo (From_Insert 'z') Nothing) ]
    (_, result) <- runBehaviorWriterT $ mdo
      counter <- foldDyn (+) 1 $ fmapMaybe (\e -> if isNothing e then Just 1 else Nothing) pulseAction
      _ <- mapMapWithAdjustWithMove
        (\_ _ -> networkHold
          (tellBehavior $ constant [])
          ((\t -> tellBehavior $ constant [t]) <$> updated counter))
        (Map.fromList $ zip [0..] "ab")
        (fmapMaybe id pulseAction)
      return ()
    return result