module State.RoomsState
  ( RoomsState,
    initRoomsState,
    HasRoomsState (..),
    roomStateDiffers,
    roomStateDiffInOpenRooms,
    updateRoomState,
    getRoomState,
  )
where

import ClassyPrelude
import State.GenericTVarState
import State.RoomDataState (MonadRoomDataStateRead (getRoomDataState))
import Types.RoomData (RoomsData, roomNotEmpty, sameName)

type RoomsState = GenericTVarState RoomsData

initRoomsState :: IO RoomsState
initRoomsState = newTVarIO []

class HasRoomsState a where
  getRoomsState :: a -> RoomsState

updateRoomState ::
  ( HasRoomsState env,
    MonadIO m,
    MonadReader env m
  ) =>
  RoomsData ->
  m ()
updateRoomState newData = do
  state <- getRoomsState <$> ask
  liftIO $ putStrLn "Upating room state"
  updateGenericTVarState state newData
  liftIO $ putStrLn "Done Upating room state"

getRoomState ::
  ( HasRoomsState env,
    MonadIO m,
    MonadReader env m
  ) =>
  m RoomsData
getRoomState = do
  state <- getRoomsState <$> ask
  getGenericTVarState state

roomStateDiffers ::
  ( MonadRoomDataStateRead m
  ) =>
  RoomsData ->
  m Bool
roomStateDiffers newData = do
  not . eqIgnoreOrdering newData <$> getRoomDataState

roomStateDiffInOpenRooms ::
  ( MonadRoomDataStateRead m,
    MonadIO m
  ) =>
  RoomsData ->
  m (RoomsData, RoomsData)
roomStateDiffInOpenRooms newData = do
  current <- getRoomDataState

  liftIO $ putStrLn $ pack $ "Current rooms: " ++ show current
  liftIO $ putStrLn $ pack $ "New rooms: " ++ show newData
  let newRooms = filter roomNotEmpty $ filter (\newRoom -> isNothing $ find (sameName newRoom) (filter roomNotEmpty current)) newData
  let oldRooms = filter roomNotEmpty $ filter (\oldRoom -> isNothing $ find (sameName oldRoom) newData) current

  return (newRooms, oldRooms)

eqIgnoreOrdering :: (Eq a) => [a] -> [a] -> Bool
eqIgnoreOrdering a b = length a == length b && all (`elem` b) a