local C=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local g=C:WaitForChild("\077\111\100\117\108\101\115")local q=require(g.src.utils.Logger)local h=require(g.src.utils.Dict)local x=require(g.src.utils.None)local t=require(g.src.utils.Print)local e=require(g.src.objects.InventoryObjects)local P=e.RoomObjects local H=require(g.src.GlobalConfig)local n=require(g.M)local l={playersWaiting={},playerVotes={};playersPlaying={};endTime=nil,countDownTime=nil,countDownText=nil}function initRoom(C)return n.extend({},l,C)end local function X(C,g)C=C or n.map(P,initRoom)if g.type=="\112\108\097\121\101\114\068\105\101\100"then q:d("\080\108\097\121\101\114 \100\105\101\100\046 \082\101\109\111\118\105\110\103 \102\114\111\109 \114\111\111\109\115\046 \077\097\114\107\105\110\103 \097\115 \068\078\070")local t local e function FindPlayerFromRoom(q,h)local x=C[h].playersPlaying local P=C[h].playersWaiting local H=x[g.playerId]local n=P[g.playerId]if H and not H.finishTime then t=h end if n then e=h end end n.each(C,FindPlayerFromRoom)if t then local x=C[t].playersPlaying q:d("\080\108\097\121\101\114 \112\108\097\121\105\110\103 "..(g.playerId.."\044 \068\078\070"))local e=h.join(x,{[g.playerId]={id=g.playerId,name=g.playerName;finishTime=os.time(),isKilled=true}})local P=h.join(C[t],{playersPlaying=e})return h.join(C,{[t]=P})end if e then local t=C[e].playersWaiting q:d("\080\108\097\121\101\114 \119\097\105\116\105\110\103 "..(g.playerId.."\046 \082\101\109\111\118\105\110\103 \102\114\111\109 \108\105\115\116"))local P=h.join(t,{[g.playerId]=x})local H=h.join(C[e],{playersWaiting=P})return h.join(C,{[e]=H})end return C elseif g.type=="\097\100\100\086\111\116\101\084\111\082\111\111\109"then local x=g.roomId local t=g.vote local e=C[x].playerVotes q:d("\065\100\100\105\110\103 \112\108\097\121\101\114 \118\111\116\101 "..(tostring(g.playerId)..(" \116\111 \114\111\111\109\058 "..x)))local P=h.join(e,{[g.playerId]=t})local H=h.join(C[x],{playerVotes=P})return h.join(C,{[x]=H})elseif g.type=="\097\100\100\080\108\097\121\101\114\084\111\082\111\111\109"then local x=g.roomId local t=C[x].playersWaiting local e=t[g.playerId]if e~=nil then q:w("\080\108\097\121\101\114 \097\108\114\101\097\100\121 \097\100\100\101\100 "..g.playerId)return C end q:d("\065\100\100\105\110\103 \112\108\097\121\101\114"..(tostring(g.playerId)..(" \116\111 \114\111\111\109\058"..x)))local P=h.join(t,{[g.playerId]={id=g.playerId;name=g.playerName}})local H=h.join(C[x],{playersWaiting=P})return h.join(C,{[x]=H})elseif g.type=="\097\100\100\080\108\097\121\101\114\070\105\110\105\115\104\084\111\082\111\111\109"then local x=g.roomId local t=C[x].playersPlaying local e=t[g.playerId]if e==nil then q:w("\078\111 \112\108\097\121\101\114 \116\111 \101\100\105\116 "..g.playerId)return C end q:d("\065\100\100\105\110\103 \112\108\097\121\101\114 "..(g.playerId..(" \102\105\110\105\115\104 \116\105\109\101 "..g.finishTime)))local P=h.join(t,{[g.playerId]={id=g.playerId;name=g.playerName;finishTime=g.finishTime;coins=g.coins}})local H=h.join(C[x],{playersPlaying=P})return h.join(C,{[x]=H})elseif g.type=="\114\101\109\111\118\101\080\108\097\121\101\114\070\114\111\109\082\111\111\109"then local t=g.roomId local e=C[t].playersWaiting local P=e[g.playerId]if P==nil then q:w("\078\111 \112\108\097\121\101\114 \116\111 \114\101\109\111\118\101 "..g.playerId)return C end local H=h.join(e,{[g.playerId]=x})local n=h.join(C[t],{playersWaiting=H})return h.join(C,{[t]=n})elseif g.type=="\115\101\116\082\111\111\109\067\111\117\110\116\068\111\119\110"then local q=g.roomId local t=h.join(C[q],{countDownTime=g.countDownTime and g.countDownTime or x,countDownText=g.text,countDownTextOther=g.textOther and g.textOther or x})return h.join(C,{[q]=t})elseif g.type=="\115\101\116\082\111\111\109\083\116\097\114\116\084\105\109\101"then local q=g.roomId local t=g.playersStarting local e=h.join(C[q],{startTime=g.startTime,endTime=x;playersWaiting={};playerVotes={},playersPlaying=t})return h.join(C,{[q]=e})elseif g.type=="\115\101\116\082\111\111\109\069\110\100\084\105\109\101"then local q=g.roomId local t=h.join(C[q],{endTime=g.startTime and g.startTime or x})return h.join(C,{[q]=t})elseif g.type=="\114\101\115\101\116\082\111\111\109"then local q=g.roomId local t=h.join(C[q],{endTime=x;startTime=x,playersPlaying={}})return h.join(C,{[q]=t})end return C end return X
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local Modules = ReplicatedStorage:WaitForChild('Modules')
local logger = require(Modules.src.utils.Logger)

local Dict = require(Modules.src.utils.Dict)
local None = require(Modules.src.utils.None)
local Print = require(Modules.src.utils.Print)
local InventoryObjects = require(Modules.src.objects.InventoryObjects)
local RoomObjects = InventoryObjects.RoomObjects
local GlobalConfig = require(Modules.src.GlobalConfig)
local M = require(Modules.M)




local roomInitial={
 
    playersWaiting = {},
    playerVotes = {},

    playersPlaying = {
        --[[  Player1 = {
            id = "1",
            finishTime = 1577984576.7429,
            name = "trimatech1"
        },
        Player2 = {
            id = "2",
            finishTime = 1577994576.7429,
            name = "trimatech2"
        },
        Player3 = {
            id = "3",
            finishTime = 1577988576.7429,
            name = "trimatech3"
        }]] --
    },
    endTime =  nil,
    --  startTime = 1577984537.9199,
    countDownTime = nil,
    countDownText = nil
}

function initRoom (roomObject)
    return M.extend({}, roomInitial, roomObject)
end

local function rooms(state, action)
    state = state or M.map(RoomObjects, initRoom)

    if action.type == "playerDied" then

        logger:d("Player died. Removing from rooms. Marking as DNF")

        local roomIdPlaying
        local roomIdWaiting


        function FindPlayerFromRoom(room, rId)
            local playersPlaying = state[rId].playersPlaying
            local playersWaiting = state[rId].playersWaiting
            local isPlayingIn = playersPlaying[action.playerId]
            local isWaitingIn = playersWaiting[action.playerId]
    
            if isPlayingIn and not isPlayingIn.finishTime then
                roomIdPlaying = rId
            end

            if isWaitingIn then
                roomIdWaiting = rId
            end
        end

         M.each(state, FindPlayerFromRoom)

         -- User can be in waiting or in playing
        if roomIdPlaying then
            local playersPlaying = state[roomIdPlaying].playersPlaying
            logger:d("Player playing " .. action.playerId .. ", DNF" )

            local newPlayers = Dict.join(playersPlaying, {
                [action.playerId] = {
                    id = action.playerId,
                    name = action.playerName,
                    finishTime = os.time(),
                    isKilled = true,
                }
            })

            local newRoom = Dict.join(state[roomIdPlaying], {playersPlaying = newPlayers})
    
            return Dict.join(state, {[roomIdPlaying] = newRoom})
        end

        if roomIdWaiting then
            local playersWaiting = state[roomIdWaiting].playersWaiting
            logger:d("Player waiting " .. action.playerId .. ". Removing from list" )

            local newPlayers = Dict.join(playersWaiting, {
                [action.playerId] = None
            })

            local newRoom = Dict.join(state[roomIdWaiting], {playersWaiting = newPlayers})
    
            return Dict.join(state, {[roomIdWaiting] = newRoom})
        end


        return state
    elseif  action.type == "addVoteToRoom" then
        local roomId = action.roomId
        local vote = action.vote
        local playerVotes = state[roomId].playerVotes
        
        logger:d("Adding player vote "..tostring(action.playerId).." to room: "..roomId )
        local newVotes = Dict.join(playerVotes, {
            [action.playerId] = vote
        })
        local newRoom = Dict.join(state[roomId], {playerVotes = newVotes})

        return Dict.join(state, {[roomId] = newRoom})
    elseif  action.type == "addPlayerToRoom" then
        local roomId = action.roomId
        local playersWaiting = state[roomId].playersWaiting
        local existingPlayer = playersWaiting[action.playerId]

        if existingPlayer ~= nil then
            logger:w("Player already added " .. action.playerId)
            return state
        end
        
        logger:d("Adding player"..tostring(action.playerId).." to room:"..roomId )
        local newPlayers = Dict.join(playersWaiting, {
            [action.playerId] = {id = action.playerId, name = action.playerName}
        })
        local newRoom = Dict.join(state[roomId], {playersWaiting = newPlayers})

        return Dict.join(state, {[roomId] = newRoom})
    elseif action.type == "addPlayerFinishToRoom" then
        local roomId = action.roomId
        local playersPlaying = state[roomId].playersPlaying
        local existingPlayer = playersPlaying[action.playerId]

        if existingPlayer == nil then
            logger:w("No player to edit " .. action.playerId)
            return state
        end
        logger:d("Adding player " .. action.playerId .. " finish time " ..
                 action.finishTime)
        local newPlayers = Dict.join(playersPlaying, {
            [action.playerId] = {
                id = action.playerId,
                name = action.playerName,
                finishTime = action.finishTime,
                coins = action.coins,

            }
        })
        local newRoom = Dict.join(state[roomId], {playersPlaying = newPlayers})

        return Dict.join(state, {[roomId] = newRoom})

    elseif action.type == "removePlayerFromRoom" then
        local roomId = action.roomId
        local playersWaiting = state[roomId].playersWaiting

        local existingPlayer = playersWaiting[action.playerId]

        if existingPlayer == nil then
            logger:w("No player to remove " .. action.playerId)
            return state
        end

        local newPlayers = Dict.join(playersWaiting, {[action.playerId] = None})
        local newRoom = Dict.join(state[roomId], {playersWaiting = newPlayers})

        return Dict.join(state, {[roomId] = newRoom})
    elseif action.type == "setRoomCountDown" then
        local roomId = action.roomId

        local newRoom = Dict.join(state[roomId], {
            countDownTime = action.countDownTime and action.countDownTime or None,
            countDownText = action.text,
            countDownTextOther = action.textOther and action.textOther or None,
        })

        return Dict.join(state, {[roomId] = newRoom})
    elseif action.type == "setRoomStartTime" then
        local roomId = action.roomId
        local playersStarting = action.playersStarting

        local newRoom = Dict.join(state[roomId], {
            startTime = action.startTime,
            endTime = None,
            playersWaiting = {},

            playerVotes={},
            playersPlaying = playersStarting
        })

        return Dict.join(state, {[roomId] = newRoom})

    elseif action.type == "setRoomEndTime" then
        local roomId = action.roomId
        local newRoom = Dict.join(state[roomId], {
            endTime = action.startTime and action.startTime or None,
        })

        return Dict.join(state, {[roomId] = newRoom})
    elseif action.type == "resetRoom" then
        local roomId = action.roomId
        local newRoom = Dict.join(state[roomId], {
            endTime = None,
            startTime = None,

            playersPlaying={}
        })

        return Dict.join(state, {[roomId] = newRoom})
    end

    return state
end

return rooms
