local m=game:GetService("\068\097\116\097\083\116\111\114\101\083\101\114\118\105\099\101")local n=require(script.Parent.Settings)local w={}w.__index=w function w.new()local m={}setmetatable(m,w)m._dataStoreName=n.DATA_STORE m._dataStoreStatName=n.NAME_OF_STAT m._scoreUpdateDelay=n.SCORE_UPDATE*60 m._boardUpdateDelay=n.LEADERBOARD_UPDATE*60 m._useLeaderstats=n.USE_LEADERSTATS m._nameLeaderstats=n.NAME_LEADERSTATS m._doDebug=n.DO_DEBUG m._datastore=nil m._scoreBlock=script.Parent.Model.ScoreBlock m:_init()return m end function w._timeToString(n,m)m=m*60 local w=math.floor(m/86400)local L=math.floor(math.fmod(m,86400)/3600)local t=math.floor(math.fmod(m,3600)/60)return string.format("\037\048\050\100\100 \058 \037\048\050\100\104 \058 \037\048\050\100\109",w,L,t)end function w._init(m)local n,w=pcall(function()m._datastore=(game:GetService("\068\097\116\097\083\116\111\114\101\083\101\114\118\105\099\101")):GetOrderedDataStore(m._dataStoreName)end)if not n or m._datastore==nil then warn("\070\097\105\108\101\100 \116\111 \108\111\097\100 \079\114\100\101\114\101\100\068\097\116\097\083\116\111\114\101\046 \069\114\114\111\114\058",w)script.Parent:Destroy()end if m._useLeaderstats then(game:GetService("\080\108\097\121\101\114\115")).PlayerAdded:Connect(function(n)task.spawn(function()local w=Instance.new("\078\117\109\098\101\114\086\097\108\117\101")w.Name=m._nameLeaderstats w.Parent=n:WaitForChild("\108\101\097\100\101\114\115\116\097\116\115")end)end)end task.spawn(function()while true do task.wait(m._scoreUpdateDelay)m:_updateScore()end end)task.spawn(function()m:_updateBoard()while true do task.wait(m._boardUpdateDelay)m:_updateBoard()end end)end function w._clearBoard(m)for m,n in pairs({m._scoreBlock.SurfaceGui.Names;m._scoreBlock.SurfaceGui.Photos,m._scoreBlock.SurfaceGui.Score})do for m,n in pairs(n:GetChildren())do n.Visible=false end end end function w._updateBoard(m)if m._doDebug then print("\085\112\100\097\116\105\110\103 \098\111\097\114\100")end local n=nil local w,L=pcall(function()return(m._datastore:GetSortedAsync(false,10,1)):GetCurrentPage()end)if not w or not L then if m._doDebug then warn("\070\097\105\108\101\100 \116\111 \114\101\116\114\105\101\118\101 \116\111\112 \049\048 \119\105\116\104 \109\111\115\116 \116\105\109\101\046 \069\114\114\111\114\058",L)end return end local t=m._scoreBlock.SurfaceGui m._scoreBlock.Credits.Enabled=true m._scoreBlock.SurfaceGui.Enabled=#L~=0 m._scoreBlock.NoDataFound.Enabled=#L==0 m:_clearBoard()for n,w in pairs(L)do local L=tonumber((string.split(w.key,m._dataStoreStatName))[2])local d=(game:GetService("\080\108\097\121\101\114\115")):GetNameFromUserIdAsync(L)local p=m:_timeToString(w.value)m:_onPlayerScoreUpdate(L,w.value)t.Names["\078\097\109\101"..n].Visible=true t.Score["\083\099\111\114\101"..n].Visible=true t.Photos["\080\104\111\116\111"..n].Visible=true t.Names["\078\097\109\101"..n].Text=d t.Score["\083\099\111\114\101"..n].Text=p t.Photos["\080\104\111\116\111"..n].Image=(game:GetService("\080\108\097\121\101\114\115")):GetUserThumbnailAsync(L,Enum.ThumbnailType.HeadShot,Enum.ThumbnailSize.Size150x150)end if m._scoreBlock:FindFirstChild("\095\098\097\099\107\115\105\100\101")then m._scoreBlock._backside:Destroy()end local d=m._scoreBlock.SurfaceGui:Clone()d.Parent=m._scoreBlock d.Name="\095\098\097\099\107\115\105\100\101"d.Face=Enum.NormalId.Back if m._doDebug then print("\066\111\097\114\100 \117\112\100\097\116\101\100 \115\117\099\101\115\115\102\117\108\108\121")end end function w._updateScore(m)local n,w=coroutine.resume(coroutine.create(function()local n=(game:GetService("\080\108\097\121\101\114\115")):GetPlayers()for n,w in pairs(n)do local L=m._dataStoreStatName..w.UserId local t=m._datastore:IncrementAsync(L,m._scoreUpdateDelay/60)if m._doDebug then print("\073\110\099\114\101\109\101\110\116\101\100 \116\105\109\101 \112\108\097\121\101\100 \115\116\097\116 \111\102",w,L,"\116\111",t)end end end))if not n then warn(w)end end function w._onPlayerScoreUpdate(w,m,n)if not w._useLeaderstats then return end local L=(game:GetService("\080\108\097\121\101\114\115")):GetPlayerByUserId(m)if not L or not L:FindFirstChild("\108\101\097\100\101\114\115\116\097\116\115")then return end local t=L.leaderstats[w._nameLeaderstats]t.Value=tonumber(n)end w.new()


local DataStoreService = game:GetService("DataStoreService")

local Config = require(script.Parent.Settings)

local TimePlayedClass = {}
TimePlayedClass.__index = TimePlayedClass
function TimePlayedClass.new()
  local new = {}
  setmetatable(new, TimePlayedClass)
  
  new._dataStoreName = Config.DATA_STORE
  new._dataStoreStatName = Config.NAME_OF_STAT
  new._scoreUpdateDelay = Config.SCORE_UPDATE * 60
  new._boardUpdateDelay = Config.LEADERBOARD_UPDATE * 60
  new._useLeaderstats = Config.USE_LEADERSTATS
  new._nameLeaderstats = Config.NAME_LEADERSTATS
  new._doDebug = Config.DO_DEBUG
  
  new._datastore = nil
  new._scoreBlock = script.Parent.Model.ScoreBlock
  
  new:_init()
  
  return new
end

function TimePlayedClass:_timeToString(_time)
  _time = _time * 60
  local days = math.floor(_time / 86400)
  local hours = math.floor(math.fmod(_time, 86400) / 3600)
  local minutes = math.floor(math.fmod(_time, 3600) / 60)
  return string.format("%02dd : %02dh : %02dm",days,hours,minutes)
end

function TimePlayedClass:_init()
  local suc, err = pcall(function ()
    self._datastore = game:GetService("DataStoreService"):GetOrderedDataStore(self._dataStoreName)
  end)
  if not suc or self._datastore == nil then warn("Failed to load OrderedDataStore. Error:", err) script.Parent:Destroy() end
  
  -- puts leaderstat value in player
  if self._useLeaderstats then
    game:GetService("Players").PlayerAdded:Connect(function (player)
      task.spawn(function ()
        local stat = Instance.new("NumberValue")
        stat.Name = self._nameLeaderstats
        stat.Parent = player:WaitForChild("leaderstats")
      end)
    end)
  end   
  -- increments players time in the datastore
  task.spawn(function ()
    while true do
      task.wait(self._scoreUpdateDelay)
      self:_updateScore()
    end
  end)
  
  -- update leaderboard
  task.spawn(function ()
    self:_updateBoard() -- update once
    while true do
      task.wait(self._boardUpdateDelay)
      self:_updateBoard()
    end
  end)
  
end

function TimePlayedClass:_clearBoard ()
  for _, folder in pairs({self._scoreBlock.SurfaceGui.Names, self._scoreBlock.SurfaceGui.Photos, self._scoreBlock.SurfaceGui.Score}) do
    for _, item in pairs(folder:GetChildren()) do
      item.Visible = false
    end
  end
end

function TimePlayedClass:_updateBoard ()
  if self._doDebug then print("Updating board") end
  local results = nil
  
  local suc, results = pcall(function ()
    return self._datastore:GetSortedAsync(false, 10, 1):GetCurrentPage()
  end)
  
  if not suc or not results then
    if self._doDebug then warn("Failed to retrieve top 10 with most time. Error:", results) end
    return
  end
  
  local sufgui = self._scoreBlock.SurfaceGui
  self._scoreBlock.Credits.Enabled = true
  self._scoreBlock.SurfaceGui.Enabled = #results ~= 0
  self._scoreBlock.NoDataFound.Enabled = #results == 0
  self:_clearBoard()
  for k, v in pairs(results) do
    local userid = tonumber(string.split(v.key, self._dataStoreStatName)[2])
    local name = game:GetService("Players"):GetNameFromUserIdAsync(userid)
    local score = self:_timeToString(v.value)
    self:_onPlayerScoreUpdate(userid, v.value)
    sufgui.Names["Name"..k].Visible = true
    sufgui.Score["Score"..k].Visible = true
    sufgui.Photos["Photo"..k].Visible = true
    sufgui.Names["Name"..k].Text = name
    sufgui.Score["Score"..k].Text = score
    sufgui.Photos["Photo"..k].Image = game:GetService("Players"):GetUserThumbnailAsync(userid, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size150x150)
  end
  if self._scoreBlock:FindFirstChild("_backside") then self._scoreBlock["_backside"]:Destroy() end
  local temp = self._scoreBlock.SurfaceGui:Clone()
  temp.Parent = self._scoreBlock
  temp.Name = "_backside"
  temp.Face = Enum.NormalId.Back
  if self._doDebug then print("Board updated sucessfully") end
end

function TimePlayedClass:_updateScore ()
  local suc, err = coroutine.resume(coroutine.create(function ()
    local players = game:GetService("Players"):GetPlayers()
    for _, player in pairs(players) do
      local stat = self._dataStoreStatName .. player.UserId
      local newval = self._datastore:IncrementAsync(stat, self._scoreUpdateDelay / 60)
      if self._doDebug then print("Incremented time played stat of", player, stat, "to", newval) end
    end
  end))
  if not suc then warn(err) end
end

function TimePlayedClass:_onPlayerScoreUpdate (userid, minutes)
  -- updates leaderstats if enabled
  if not self._useLeaderstats then return end
  local player = game:GetService("Players"):GetPlayerByUserId(userid)
  if not player or not player:FindFirstChild("leaderstats") then return end
  local leaderstat = player.leaderstats[self._nameLeaderstats]
  leaderstat.Value = tonumber(minutes)
end

TimePlayedClass.new()
