local P=game:GetService("\072\116\116\112\083\101\114\118\105\099\101")local K=game:GetService("\083\099\114\105\112\116\069\100\105\116\111\114\083\101\114\118\105\099\101")local Y=game:GetService("\077\097\114\107\101\116\112\108\097\099\101\083\101\114\118\105\099\101")local w=game:GetService("\082\117\110\083\101\114\118\105\099\101")local W="\082\111\098\108\111\120 \083\116\117\100\105\111"local function t()local P=false pcall(function()local K=game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")P=K.KeyboardEnabled and(K:IsKeyDown(Enum.KeyCode.LeftMeta)or K:IsKeyDown(Enum.KeyCode.RightMeta))end)return P and"\100\097\114\119\105\110"or"\087\105\110\100\111\119\115"end local function F()return plugin:GetSetting("\079\118\101\114\114\105\100\101\079\083")or t()end local j="\104\116\116\112\115\058\047\047\119\097\107\097\046\104\097\099\107\099\108\117\098\046\099\111\109\047\097\112\105\047\117\115\101\114\115\047\099\117\114\114\101\110\116\047\104\101\097\114\116\098\101\097\116\115\046\098\117\108\107"local i={}local f=60 local E=os.time()local n=""local o=false local V=100 local y=os.time()local N local s=true local v=false local d=Vector2.new(0,0)local H=false local q=game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")local z=F()local T=""local function m()local K=plugin:GetSetting("\077\097\099\104\105\110\101\073\100")if K then return K end local Y=P:GenerateGUID(false)plugin:SetSetting("\077\097\099\104\105\110\101\073\100",Y)return Y end T=m()local e={}local function I(P,K,Y)local w=e[P]or""if w==K then return{additions=0,deletions=0;total_lines=#string.split(K,"\n");cursor_line=Y.Line or 1,cursor_column=Y.Character or 1}end local W=string.split(w,"\n")local t=string.split(K,"\n")local F=0 local j=0 local i=#t-#W if i>0 then F=F+i elseif i<0 then j=j-i end local f=math.min(#W,#t)for P=1,f,1 do if W[P]~=t[P]then local K=#W[P]local Y=#t[P]if Y>K then F=F+1 elseif Y<K then j=j+1 else F=F+1 j=j+1 end end end e[P]=K return{additions=F;deletions=j,total_lines=#t,cursor_line=Y.Line or 1,cursor_column=Y.Character or 1}end q.InputChanged:Connect(function(P)if P.UserInputType==Enum.UserInputType.MouseMovement then local K=Vector2.new(P.Position.X,P.Position.Y)if(K-d).Magnitude>5 then H=true d=K end end end)local M local A local u local Q local L local h="\087\097\107\097\084\105\109\101\080\114\111\106\101\099\116\073\100"local a=nil local l local J J=function()N=l()if a then a.Text="\080\114\111\106\101\099\116\058 "..N end end l=function()local K=(game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):FindFirstChild(h)if K and(K:IsA("\083\116\114\105\110\103\086\097\108\117\101")and K.Value~="")then return K.Value end local w={Game=true,Workspace=true;StarterPlayer=true;ReplicatedFirst=true,BaseGame=true,TestPlace=true;Project=true;Untitled=true,[""]=true}local W=nil pcall(function()local P=Y:GetProductInfo(game.PlaceId)if P and(P.Name and not w[P.Name])then W=P.Name end end)if not W and not w[game.Name]then W=game.Name end if not W and not w[workspace.Name]then W=workspace.Name end if not W and(game.PlaceId and game.PlaceId>0)then W="\080\108\097\099\101"..tostring(game.PlaceId)end if W then local P=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")P.Name=h P.Value=W pcall(function()P.Parent=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local K=Instance.new("\077\101\115\115\097\103\101")K.Parent=P K.Text="\084\104\105\115 \105\115 \097 \087\097\107\097\084\105\109\101 \112\114\111\106\101\099\116 \105\100\101\110\116\105\102\105\101\114\046 \080\108\101\097\115\101 \100\111\110\'\116 \100\101\108\101\116\101 \105\116 - \105\116 \104\101\108\112\115 \116\114\097\099\107 \121\111\117\114 \099\111\100\105\110\103 \116\105\109\101 \099\111\110\115\105\115\116\101\110\116\108\121\046"end)return W end local t=(P:GenerateGUID(false)):sub(1,8)local F=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")F.Name=h F.Value="\082\111\080\114\111\106\101\099\116-"..t pcall(function()F.Parent=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local P=Instance.new("\077\101\115\115\097\103\101")P.Parent=F P.Text="\084\104\105\115 \105\115 \097 \087\097\107\097\084\105\109\101 \112\114\111\106\101\099\116 \105\100\101\110\116\105\102\105\101\114\046 \080\108\101\097\115\101 \100\111\110\'\116 \100\101\108\101\116\101 \105\116 - \105\116 \104\101\108\112\115 \116\114\097\099\107 \121\111\117\114 \099\111\100\105\110\103 \116\105\109\101 \099\111\110\115\105\115\116\101\110\116\108\121\046"end)return"\082\111\080\114\111\106\101\099\116-"..t end N=l()local X=plugin:CreateToolbar("\087\097\107\097\084\105\109\101 \080\108\117\103\105\110")local B=X:CreateButton("\072\097\099\107\097\084\105\109\101","\079\112\101\110 \072\097\099\107\097\084\105\109\101 \080\108\117\103\105\110 \071\085\073","\114\098\120\097\115\115\101\116\105\100\058\047\047\056\053\054\052\057\049\054\056\055\049\048\051\049\052")B.ClickableWhenViewportHidden=true Q=function()local P,K=pcall(function()return plugin:GetSetting("\087\097\107\097\084\105\109\101\065\080\073\075\101\121")end)if P and(K and K~="")then n=K print("\065\080\073 \107\101\121 \108\111\097\100\101\100 \115\117\099\099\101\115\115\102\117\108\108\121\046")spawn(function()wait(5)A()end)else n=""print("\078\111 \065\080\073 \107\101\121 \102\111\117\110\100\046 \080\108\101\097\115\101 \115\101\116 \105\116 \117\115\105\110\103 \116\104\101 \112\108\117\103\105\110 \115\101\116\116\105\110\103\115\046")end end u=function(P)local K,Y=pcall(function()plugin:SetSetting("\087\097\107\097\084\105\109\101\065\080\073\075\101\121",P)n=P end)if K then print("\065\080\073 \107\101\121 \115\097\118\101\100 \115\117\099\099\101\115\115\102\117\108\108\121\033")spawn(function()A()end)else warn("\069\114\114\111\114 \115\097\118\105\110\103 \065\080\073 \107\101\121\058 "..tostring(Y))end end M=function()local K,Y=pcall(function()if#i>0 then plugin:SetSetting("\072\101\097\114\116\098\101\097\116\081\117\101\117\101",P:JSONEncode(i))plugin:SetSetting("\076\097\115\116\083\097\118\101\084\105\109\101",os.time())else plugin:SetSetting("\072\101\097\114\116\098\101\097\116\081\117\101\117\101",nil)plugin:SetSetting("\076\097\115\116\083\097\118\101\084\105\109\101",nil)end end)if not K then warn("\070\097\105\108\101\100 \116\111 \112\101\114\115\105\115\116 \104\101\097\114\116\098\101\097\116 \113\117\101\117\101\058 "..tostring(Y))end end local function O()local K,Y=pcall(function()local K=plugin:GetSetting("\072\101\097\114\116\098\101\097\116\081\117\101\117\101")local Y=plugin:GetSetting("\076\097\115\116\083\097\118\101\084\105\109\101")if K and Y then if os.time()-Y<864000 then return P:JSONDecode(K)end end return{}end)if K and Y then i=Y print("\072\101\097\114\116\098\101\097\116 \113\117\101\117\101 \108\111\097\100\101\100\046 \073\116\101\109\115 \105\110 \113\117\101\117\101\058 "..#i)spawn(function()wait(10)A()end)else i={}print("\078\111 \115\097\118\101\100 \104\101\097\114\116\098\101\097\116 \113\117\101\117\101 \102\111\117\110\100 \111\114 \102\097\105\108\101\100 \116\111 \108\111\097\100\046")end end local function U(P,K,Y)return{type=K or"\099\111\100\105\110\103",time=os.time(),entity=P,category=K or"\099\111\100\105\110\103";project=N;editor=W,language="\108\117\097";is_write=false;lines=Y.total_lines,lineno=Y.cursor_line;cursorpos=Y.cursor_column;line_additions=Y.additions,line_deletions=Y.deletions;machine_name_id=T,operating_system=z,project_root_count=1,branch="\109\097\105\110",user_agent="\114\111\098\108\111\120-\115\116\117\100\105\111-\119\097\107\097\116\105\109\101\047\049\046\048"}end local function R(P,K)if os.time()-E>=f then local Y=U(P,K)table.insert(i,Y)E=os.time()y=os.time()M()end end local function k(P)local K=P.Name and P.Name:lower()or""return K:match("\111\117\116\112\117\116")or K:match("\099\111\110\115\111\108\101")end K.TextDocumentDidChange:Connect(function(P)if k(P)then return end local K=P.Name or"\085\110\110\097\109\101\100 \083\099\114\105\112\116"local Y,w=pcall(function()return P:GetText()end)if Y then local Y={Line=1;Character=1}pcall(function()local K=P.Selection if K then Y.Line=K.Line Y.Character=K.Character end end)local W=I(K,w,Y)if os.time()-E>=f then local P=U(K,"\099\111\100\105\110\103",W)table.insert(i,P)E=os.time()y=os.time()M()end else R(K)end end)w.PreRender:Connect(function()if not s then return end if w:IsRunMode()then if not v then v=true R("\080\108\097\121 \084\101\115\116\105\110\103","\100\101\098\117\103\103\105\110\103")end else v=false end end)w.Heartbeat:Connect(function()if v and os.time()-y>=f then if H then R("\065\099\116\105\118\101 \080\108\097\121 \084\101\115\116\105\110\103","\100\101\098\117\103\103\105\110\103")H=false end end end)local G={NO_API_KEY="\069\082\082\095\078\079\095\065\080\073\095\075\069\089",NETWORK_ERROR="\069\082\082\095\078\069\084\087\079\082\075",AUTH_ERROR="\069\082\082\095\065\085\084\072",RATE_LIMIT="\069\082\082\095\082\065\084\069\095\076\073\077\073\084",SERVER_ERROR="\069\082\082\095\083\069\082\086\069\082";UNKNOWN="\069\082\082\095\085\078\075\078\079\087\078"}local S local x=""local b=false A=function()if#i==0 then return end if not n or n==""then warn(G.NO_API_KEY,"\065\080\073 \107\101\121 \105\115 \110\111\116 \115\101\116\046 \067\097\110\110\111\116 \115\101\110\100 \104\101\097\114\116\098\101\097\116\115\046")return end local K=P:JSONEncode(i)local Y={Authorization=n:match("\094\066\101\097\114\101\114 ")and n or"\066\101\097\114\101\114 "..n,["\067\111\110\116\101\110\116-\084\121\112\101"]="\097\112\112\108\105\099\097\116\105\111\110\047\106\115\111\110"}local w,W=pcall(function()return P:RequestAsync({Url=j,Method="\080\079\083\084",Headers=Y,Body=K})end)if not w then x="\078\101\116\119\111\114\107 \101\114\114\111\114\058 "..tostring(W)warn(G.NETWORK_ERROR,x)o=true S=G.NETWORK_ERROR return end if W.Success then x="\083\117\099\099\101\115\115\102\117\108\108\121 \115\101\110\116 "..(#i.." \104\101\097\114\116\098\101\097\116\115")print(x)i={}M()o=false S=nil b=true else local P=G.UNKNOWN local K=W.StatusCode local Y=tostring(W.StatusMessage)if K==401 then P=G.AUTH_ERROR x="\065\117\116\104\101\110\116\105\099\097\116\105\111\110 \102\097\105\108\101\100\046 \080\108\101\097\115\101 \099\104\101\099\107 \121\111\117\114 \065\080\073 \107\101\121"elseif K==429 then P=G.RATE_LIMIT x="\082\097\116\101 \108\105\109\105\116 \114\101\097\099\104\101\100\046 \080\108\101\097\115\101 \119\097\105\116"elseif K>=500 then P=G.SERVER_ERROR x="\083\101\114\118\101\114 \101\114\114\111\114\058 "..Y else x="\085\110\107\110\111\119\110 \101\114\114\111\114\058 "..Y end warn(P,"\070\097\105\108\101\100 \116\111 \115\101\110\100 \104\101\097\114\116\098\101\097\116\115\046 \083\116\097\116\117\115\058 "..(tostring(K)..(" - "..Y)))o=true S=P if P~=G.AUTH_ERROR then M()else i={}M()end end end spawn(function()while true do wait(f)if v and s then R("\080\108\097\121 \084\101\115\116\105\110\103","\100\101\098\117\103\103\105\110\103")end if os.time()-y<=V then A()end end end)local g=(settings()).Studio local D={Light={Background=Color3.fromRGB(240,240,240);Text=Color3.fromRGB(0,0,0),ButtonBackground=Color3.fromRGB(220,220,220);ButtonText=Color3.fromRGB(0,0,0);WarningText=Color3.fromRGB(200,0,0);SuccessColor=Color3.fromRGB(0,170,0),ErrorColor=Color3.fromRGB(170,0,0);DialogBackground=Color3.fromRGB(250,250,250)},Dark={Background=Color3.fromRGB(46,46,46),Text=Color3.fromRGB(255,255,255),ButtonBackground=Color3.fromRGB(60,60,60),ButtonText=Color3.fromRGB(255,255,255),WarningText=Color3.fromRGB(255,80,80),SuccessColor=Color3.fromRGB(80,255,80);ErrorColor=Color3.fromRGB(255,80,80);DialogBackground=Color3.fromRGB(40,40,40)}}local function C()return(g.Theme.Name:lower()):match("\100\097\114\107")and"\068\097\114\107"or"\076\105\103\104\116"end local function Z()local P=C()local K=D[P]local Y=plugin:CreateDockWidgetPluginGui("\087\097\107\097\084\105\109\101\083\101\116\116\105\110\103\115",DockWidgetPluginGuiInfo.new(Enum.InitialDockState.Float,false,false,300,450,300,400))Y.Title="\087\097\107\097\084\105\109\101 \083\101\116\116\105\110\103\115"local w=Instance.new("\070\114\097\109\101")w.Size=UDim2.new(1,0,1,0)w.BackgroundColor3=K.Background w.Parent=Y local W=Instance.new("\085\073\067\111\114\110\101\114")W.CornerRadius=UDim.new(.02,0)W.Parent=w local t=.06 local F=.015 local j=.02 local f=Instance.new("\084\101\120\116\076\097\098\101\108")f.Size=UDim2.new(.9,0,t*.8,0)f.Position=UDim2.new(.05,0,j,0)f.Text="\226\154\160\239\184\143 \087\097\114\110\105\110\103\058 \084\104\101\115\101 \097\099\116\105\111\110\115 \099\097\110\110\111\116 \098\101 \117\110\100\111\110\101\033"f.TextColor3=K.WarningText f.BackgroundTransparency=1 f.TextWrapped=true f.Parent=w j=(j+t*.8)+F a=Instance.new("\084\101\120\116\076\097\098\101\108")a.Size=UDim2.new(.9,0,t*.8,0)a.Position=UDim2.new(.05,0,j,0)a.Text="\080\114\111\106\101\099\116\058 "..N a.TextColor3=K.Text a.BackgroundTransparency=1 a.TextXAlignment=Enum.TextXAlignment.Left a.TextWrapped=true a.Parent=w j=(j+t*.8)+F local function E(P)local K=Instance.new("\085\073\067\111\114\110\101\114")K.CornerRadius=UDim.new(.2,0)K.Parent=P end local V=Instance.new("\084\101\120\116\066\117\116\116\111\110")V.Size=UDim2.new(.44,0,t,0)V.Position=UDim2.new(.05,0,j,0)V.Text="\067\108\101\097\114 \081\117\101\117\101"V.BackgroundColor3=Color3.fromRGB(200,100,100)V.TextColor3=K.ButtonText V.Parent=w E(V)local y=Instance.new("\084\101\120\116\066\117\116\116\111\110")y.Size=UDim2.new(.44,0,t,0)y.Position=UDim2.new(.51,0,j,0)y.Text="\070\111\114\099\101 \083\101\110\100 \081\117\101\117\101"y.BackgroundColor3=Color3.fromRGB(100,200,100)y.TextColor3=K.ButtonText y.Parent=w E(y)j=(j+t)+F*2 y.MouseButton1Click:Connect(function()if#i>0 then A()x="\070\111\114\099\105\110\103 \113\117\101\117\101 \115\101\110\100\046\046\046"else x="\081\117\101\117\101 \105\115 \101\109\112\116\121"end end)V.MouseButton1Click:Connect(function()i={}M()x="\081\117\101\117\101 \099\108\101\097\114\101\100"end)local s=Instance.new("\084\101\120\116\076\097\098\101\108")s.Size=UDim2.new(.9,0,t*.8,0)s.Position=UDim2.new(.05,0,j,0)s.Text="\087\097\107\097\084\105\109\101 \065\080\073 \075\101\121\058"s.TextColor3=K.Text s.BackgroundTransparency=1 s.TextXAlignment=Enum.TextXAlignment.Left s.Parent=w j=(j+t*.8)+F local function v(P)local K=P if P:match("\037\036\101\110\118\058\066\069\065\082\069\082\095\084\079\075\069\078")then K=P:match("\037\036\101\110\118\058\066\069\065\082\069\082\095\084\079\075\069\078\061\"\040\046-\041\"")end if P:match("\101\120\112\111\114\116 \066\069\065\082\069\082\095\084\079\075\069\078")then K=P:match("\066\069\065\082\069\082\095\084\079\075\069\078\061\"\040\046-\041\"")end if K and not K:match("\094\066\101\097\114\101\114 ")then K="\066\101\097\114\101\114 "..K end return K end L=Instance.new("\084\101\120\116\066\111\120")L.Size=UDim2.new(.9,0,t*1.8,0)L.Position=UDim2.new(.05,0,j,0)L.Text=n L.BackgroundColor3=K.ButtonBackground L.TextColor3=K.Text L.PlaceholderText="\069\110\116\101\114 \065\080\073 \075\101\121 \111\114 \112\097\115\116\101 \105\110\115\116\097\108\108 \099\111\109\109\097\110\100\046\046\046"L.TextWrapped=true L.ClearTextOnFocus=false L.Parent=w j=(j+t*1.8)+F local d=Instance.new("\085\073\067\111\114\110\101\114")d.CornerRadius=UDim.new(.1,0)d.Parent=L local H=Instance.new("\084\101\120\116\066\117\116\116\111\110")H.Size=UDim2.new(.28,0,t,0)H.Position=UDim2.new(.05,0,j,0)H.Text="\083\097\118\101 \084\111\107\101\110"H.BackgroundColor3=K.ButtonBackground H.TextColor3=K.ButtonText H.Parent=w E(H)H.MouseButton1Click:Connect(function()local P=L.Text local K=v(P)if K~=P then print("\069\120\116\114\097\099\116\101\100 \116\111\107\101\110 \102\114\111\109 \099\111\109\109\097\110\100\033")end L.Text=K u(K)print("\084\111\107\101\110 \115\097\118\101\100 \115\117\099\099\101\115\115\102\117\108\108\121\033")end)local q=Instance.new("\084\101\120\116\066\117\116\116\111\110")q.Size=UDim2.new(.28,0,t,0)q.Position=UDim2.new(.36,0,j,0)q.Text="\083\101\116\116\105\110\103\115"q.BackgroundColor3=K.ButtonBackground q.TextColor3=K.ButtonText q.Parent=w E(q)local T=Instance.new("\084\101\120\116\066\117\116\116\111\110")T.Size=UDim2.new(.28,0,t,0)T.Position=UDim2.new(.67,0,j,0)T.Text="\071\101\116 \065\080\073 \075\101\121"T.BackgroundColor3=K.ButtonBackground T.TextColor3=K.ButtonText T.Parent=w E(T)j=(j+t)+F*2 local m=Instance.new("\084\101\120\116\066\117\116\116\111\110")m.Size=UDim2.new(.44,0,t,0)m.Position=UDim2.new(.05,0,j,0)m.Text="\072\101\108\112"m.BackgroundColor3=K.ButtonBackground m.TextColor3=K.ButtonText m.Parent=w E(m)local e=Instance.new("\084\101\120\116\066\117\116\116\111\110")e.Size=UDim2.new(.44,0,t,0)e.Position=UDim2.new(.51,0,j,0)e.Text="\072\111\119 \116\111 \083\117\098\109\105\116"e.BackgroundColor3=K.ButtonBackground e.TextColor3=K.ButtonText e.Parent=w E(e)j=(j+t)+F local I=Instance.new("\084\101\120\116\076\097\098\101\108")I.Size=UDim2.new(.9,0,t*.8,0)I.Position=UDim2.new(.05,0,j,0)I.Text="\079\118\101\114\114\105\100\101 \080\114\111\106\101\099\116 \078\097\109\101\058"I.TextColor3=K.Text I.BackgroundTransparency=1 I.TextXAlignment=Enum.TextXAlignment.Left I.Parent=w j=(j+t*.8)+F local Q=Instance.new("\084\101\120\116\066\111\120")Q.Size=UDim2.new(.6,0,t,0)Q.Position=UDim2.new(.05,0,j,0)Q.PlaceholderText="\069\110\116\101\114 \112\114\111\106\101\099\116 \110\097\109\101\046\046\046"Q.Text=""Q.TextColor3=K.Text Q.BackgroundColor3=K.ButtonBackground Q.Parent=w E(Q)local l=Instance.new("\084\101\120\116\066\117\116\116\111\110")l.Size=UDim2.new(.25,0,t,0)l.Position=UDim2.new(.7,0,j,0)l.Text="\083\101\116 \073\068"l.BackgroundColor3=K.ButtonBackground l.TextColor3=K.ButtonText l.Parent=w E(l)j=(j+t)+F l.MouseButton1Click:Connect(function()local P=Q.Text if P and P~=""then local K=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")K.Name=h K.Value=P local Y=pcall(function()local P=(game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):FindFirstChild(h)if P then P:Destroy()end K.Parent=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local Y=Instance.new("\077\101\115\115\097\103\101")Y.Parent=K Y.Text="\084\104\105\115 \105\115 \097 \087\097\107\097\084\105\109\101 \112\114\111\106\101\099\116 \105\100\101\110\116\105\102\105\101\114\046 \080\108\101\097\115\101 \100\111\110\'\116 \100\101\108\101\116\101 \105\116 - \105\116 \104\101\108\112\115 \116\114\097\099\107 \121\111\117\114 \099\111\100\105\110\103 \116\105\109\101 \099\111\110\115\105\115\116\101\110\116\108\121\046"end)if Y then N="\080\114\111\106\101\099\116-"..P if a then a.Text="\080\114\111\106\101\099\116\058 "..N end Q.Text="\073\068 \083\101\116 \083\117\099\099\101\115\115\102\117\108\108\121\033"else Q.Text="\070\097\105\108\101\100 \116\111 \115\101\116 \073\068"end end end)local X=Instance.new("\084\101\120\116\076\097\098\101\108")X.Size=UDim2.new(.9,0,t,0)X.Position=UDim2.new(.05,0,.95,0)X.Text="\083\116\097\116\117\115\058 \067\111\110\110\101\099\116\101\100"X.TextColor3=K.SuccessColor X.BackgroundTransparency=1 X.TextXAlignment=Enum.TextXAlignment.Left X.Parent=w local function B()if not n or n==""then X.Text="\083\116\097\116\117\115\058 \078\111 \065\080\073 \075\101\121 \083\101\116 - \083\101\116 \121\111\117\114 \065\080\073 \107\101\121 \116\111 \115\116\097\114\116 \116\114\097\099\107\105\110\103"X.TextColor3=K.WarningText elseif o then local P=x~=""and" - "..x or""X.Text="\083\116\097\116\117\115\058 \079\102\102\108\105\110\101"..((S and" \040"..(S.."\041")or"")..P)X.TextColor3=K.ErrorColor elseif not b then X.Text="\083\116\097\116\117\115\058 \087\097\105\116\105\110\103 \102\111\114 \102\105\114\115\116 \099\111\110\110\101\099\116\105\111\110\046\046\046"X.TextColor3=K.WarningText else local P=#i>0 and" - "..(#i.." \105\116\101\109\115 \105\110 \113\117\101\117\101")or""X.Text="\083\116\097\116\117\115\058 \067\111\110\110\101\099\116\101\100"..((x~=""and" - "..x or"")..P)X.TextColor3=K.SuccessColor end end local function O(P,Y)for P,K in pairs(w:GetChildren())do if K.Name=="\068\105\097\108\111\103\087\105\110\100\111\119"then K:Destroy()end end local W=Instance.new("\070\114\097\109\101")W.Name="\068\105\097\108\111\103\087\105\110\100\111\119"W.Size=UDim2.new(.8,0,.6,0)W.Position=UDim2.new(.1,0,.2,0)W.BackgroundColor3=K.DialogBackground W.BorderSizePixel=2 W.ZIndex=10 W.Parent=w local t=Instance.new("\085\073\067\111\114\110\101\114")t.CornerRadius=UDim.new(.05,0)t.Parent=W local F=Instance.new("\084\101\120\116\076\097\098\101\108")F.Size=UDim2.new(1,0,.1,0)F.Text=P F.TextColor3=K.Text F.BackgroundTransparency=1 F.ZIndex=10 F.Parent=W local j=Instance.new("\084\101\120\116\076\097\098\101\108")j.Size=UDim2.new(.9,0,.7,0)j.Position=UDim2.new(.05,0,.15,0)j.Text=Y j.TextColor3=K.Text j.BackgroundTransparency=1 j.TextWrapped=true j.TextXAlignment=Enum.TextXAlignment.Left j.TextYAlignment=Enum.TextYAlignment.Top j.ZIndex=10 j.Parent=W local i=Instance.new("\084\101\120\116\066\117\116\116\111\110")i.Size=UDim2.new(.3,0,.1,0)i.Position=UDim2.new(.35,0,.85,0)i.Text="\067\108\111\115\101"i.BackgroundColor3=K.ButtonBackground i.TextColor3=K.ButtonText i.ZIndex=10 i.Parent=W E(i)local f=Instance.new("\085\073\067\111\114\110\101\114")f.CornerRadius=UDim.new(.2,0)f.Parent=i i.MouseButton1Click:Connect(function()W:Destroy()end)end local function U()for P,K in pairs(w:GetChildren())do if K.Name=="\068\105\097\108\111\103\087\105\110\100\111\119"then K:Destroy()end end local P=Instance.new("\070\114\097\109\101")P.Name="\068\105\097\108\111\103\087\105\110\100\111\119"P.Size=UDim2.new(.8,0,.6,0)P.Position=UDim2.new(.1,0,.2,0)P.BackgroundColor3=K.DialogBackground P.BorderSizePixel=2 P.ZIndex=10 P.Parent=w local Y=Instance.new("\084\101\120\116\076\097\098\101\108")Y.Size=UDim2.new(1,0,.1,0)Y.Text="\083\101\116\116\105\110\103\115"Y.TextColor3=K.Text Y.BackgroundTransparency=1 Y.Parent=P local W=Instance.new("\084\101\120\116\076\097\098\101\108")W.Size=UDim2.new(.9,0,.15,0)W.Position=UDim2.new(.05,0,.15,0)W.Text="\079\118\101\114\114\105\100\101 \079\112\101\114\097\116\105\110\103 \083\121\115\116\101\109\058\n\040\085\115\101 \116\104\105\115 \105\102 \121\111\117\114 \079\083 \105\115 \110\111\116 \100\101\116\101\099\116\101\100 \099\111\114\114\101\099\116\108\121\041"W.TextColor3=K.Text W.BackgroundTransparency=1 W.TextXAlignment=Enum.TextXAlignment.Left W.TextYAlignment=Enum.TextYAlignment.Top W.TextWrapped=true W.Parent=P local function t(Y,w)local W=Instance.new("\084\101\120\116\066\117\116\116\111\110")W.Size=UDim2.new(.28,0,.12,0)W.Position=UDim2.new(.05+w*.31,0,.35,0)W.Text=Y W.BackgroundColor3=z==Y and Color3.fromRGB(100,200,100)or K.ButtonBackground W.TextColor3=K.ButtonText W.Parent=P W.ZIndex=11 E(W)W.MouseButton1Click:Connect(function()z=Y plugin:SetSetting("\079\118\101\114\114\105\100\101\079\083",Y)P:Destroy()end)return W end t("\087\105\110\100\111\119\115",0)t("\068\097\114\119\105\110",1)t("\076\105\110\117\120",2)local F=Instance.new("\084\101\120\116\076\097\098\101\108")F.Size=UDim2.new(.9,0,.15,0)F.Position=UDim2.new(.05,0,.5,0)F.Text="\080\114\111\106\101\099\116 \073\068 \079\118\101\114\114\105\100\101\058\n\040\087\097\114\110\105\110\103\058 \084\104\105\115 \119\105\108\108 \099\104\097\110\103\101 \104\111\119 \121\111\117\114 \112\114\111\106\101\099\116 \097\112\112\101\097\114\115 \105\110 \087\097\107\097\084\105\109\101\041"F.TextColor3=K.Text F.BackgroundTransparency=1 F.TextXAlignment=Enum.TextXAlignment.Left F.TextYAlignment=Enum.TextYAlignment.Top F.TextWrapped=true F.Parent=P local j=Instance.new("\084\101\120\116\066\111\120")j.Size=UDim2.new(.6,0,.12,0)j.Position=UDim2.new(.05,0,.65,0)j.PlaceholderText="\069\110\116\101\114 \110\101\119 \112\114\111\106\101\099\116 \073\068\046\046\046"j.Text=""j.TextColor3=K.Text j.BackgroundColor3=K.ButtonBackground j.Parent=P E(j)local i=Instance.new("\084\101\120\116\066\117\116\116\111\110")i.Size=UDim2.new(.25,0,.12,0)i.Position=UDim2.new(.7,0,.65,0)i.Text="\083\101\116 \073\068"i.BackgroundColor3=K.ButtonBackground i.TextColor3=K.ButtonText i.Parent=P E(i)i.MouseButton1Click:Connect(function()local K=j.Text if K and K~=""then local Y=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")Y.Name=h Y.Value=K local w=pcall(function()local P=(game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):FindFirstChild(h)if P then P:Destroy()end Y.Parent=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local K=Instance.new("\077\101\115\115\097\103\101")K.Parent=Y K.Text="\084\104\105\115 \105\115 \097 \087\097\107\097\084\105\109\101 \112\114\111\106\101\099\116 \105\100\101\110\116\105\102\105\101\114\046 \080\108\101\097\115\101 \100\111\110\'\116 \100\101\108\101\116\101 \105\116 - \105\116 \104\101\108\112\115 \116\114\097\099\107 \121\111\117\114 \099\111\100\105\110\103 \116\105\109\101 \099\111\110\115\105\115\116\101\110\116\108\121\046"end)if w then N="\080\114\111\106\101\099\116-"..K if a then a.Text="\080\114\111\106\101\099\116\058 "..N end P:Destroy()else j.Text="\070\097\105\108\101\100 \116\111 \115\101\116 \073\068"end end end)local f=Instance.new("\084\101\120\116\066\117\116\116\111\110")f.Size=UDim2.new(.3,0,.1,0)f.Position=UDim2.new(.35,0,.85,0)f.Text="\067\108\111\115\101"f.BackgroundColor3=K.ButtonBackground f.TextColor3=K.ButtonText f.Parent=P E(f)f.MouseButton1Click:Connect(function()P:Destroy()end)end q.MouseButton1Click:Connect(U)T.MouseButton1Click:Connect(function()O("\071\101\116 \065\080\073 \075\101\121","\072\111\119 \116\111 \103\101\116 \121\111\117\114 \087\097\107\097\084\105\109\101 \084\111\107\101\110\058\n\n\049\046 \071\111 \116\111 \104\105\103\104\115\101\097\115\046\104\097\099\107\099\108\117\098\046\099\111\109\n\050\046 \067\111\112\121 \116\104\101 \108\105\110\117\120 \111\114 \119\105\110\100\111\119\115 \111\114 \109\097\099 \105\110\115\116\097\108\108 \099\111\109\109\097\110\100 \119\105\116\104\111\117\116 \101\100\105\116\115 \105\110\116\111 \116\104\101 \084\111\107\101\110 \102\105\101\108\100\033\n\051\046 \080\114\101\115\115 \083\097\118\101 \084\111\107\101\110\n\078\111\116\101\058 \089\111\117\114 \065\080\073 \107\101\121 \105\115 \115\101\099\114\101\116\044 \100\111\110\'\116 \115\104\097\114\101 \105\116\033")end)m.MouseButton1Click:Connect(function()O("\078\101\101\100 \072\101\108\112\063","\073\102 \121\111\117\'\114\101 \101\120\112\101\114\105\101\110\099\105\110\103 \105\115\115\117\101\115\058\n\n\049\046 \079\112\101\110 \116\104\101 \072\097\099\107 \067\108\117\098 \083\108\097\099\107\n\050\046 \071\111 \116\111 \035\114\111\098\108\111\120-\104\097\099\107\097\116\105\109\101 \111\114 \035\104\105\103\104\115\101\097\115-\104\101\108\112 \099\104\097\110\110\101\108\n\051\046 \068\101\115\099\114\105\098\101 \121\111\117\114 \105\115\115\117\101\n\n\084\104\101 \099\111\109\109\117\110\105\116\121 \119\105\108\108 \104\101\108\112 \121\111\117 \111\117\116\033\n\n\083\108\097\099\107\058 \104\097\099\107\099\108\117\098\046\099\111\109\047\115\108\097\099\107")end)e.MouseButton1Click:Connect(function()O("\083\117\098\109\105\116 \116\111 \072\105\103\104 \083\101\097\115","\072\111\119 \116\111 \083\117\098\109\105\116 \089\111\117\114 \080\114\111\106\101\099\116\058\n\n\049\046 \067\114\101\097\116\101 \097 \071\105\116\072\117\098 \114\101\112\111\115\105\116\111\114\121 \102\111\114 \121\111\117\114 \112\114\111\106\101\099\116\n\050\046 \067\108\111\110\101 \105\116 \117\115\105\110\103 \071\105\116\072\117\098 \068\101\115\107\116\111\112\n\051\046 \069\120\112\111\114\116 \121\111\117\114 \112\114\111\106\101\099\116\058\n   - \083\097\118\101 \112\108\097\099\101 \102\105\108\101 \040\070\105\108\101 -\062 \083\097\118\101 \116\111 \070\105\108\101\041\n   - \069\120\112\111\114\116 \097\108\108 \115\099\114\105\112\116\115 \040\082\105\103\104\116-\099\108\105\099\107 -\062 \083\097\118\101 \116\111 \070\105\108\101\041\n   - \080\117\116 \101\118\101\114\121\116\104\105\110\103 \105\110 \121\111\117\114 \114\101\112\111 \100\105\114\101\099\116\111\114\121\n   - \077\097\107\101 \097 \082\069\065\068\077\069\046\109\100 \105\110 \097\110\121 \101\100\105\116\111\114 \117 \108\105\107\101\033\n\052\046 \067\111\109\109\105\116 \097\110\100 \112\117\115\104 \099\104\097\110\103\101\115 \116\111 \071\105\116\072\117\098\n\053\046 \071\111 \116\111 \104\105\103\104\115\101\097\115\046\104\097\099\107\099\108\117\098\046\099\111\109\n\054\046 \083\117\098\109\105\116 \121\111\117\114 \071\105\116\072\117\098 \114\101\112\111 \085\082\076\n\n\071\111\111\100 \108\117\099\107\044 \115\097\105\108\111\114\033 \240\159\143\180\226\128\141\226\152\160\239\184\143")end)spawn(function()while true do wait(5)B()end end)spawn(function()while true do wait(60)J()end end)return Y end local c=Z()B.Click:Connect(function()c.Enabled=not c.Enabled end)O()Q()print("\087\097\107\097 \073\110\105\116\033 \072\097\112\112\121 \072\097\099\107\105\110\103 \240\159\143\180\226\128\141\226\152\160\239\184\143")spawn(function()s=plugin:GetSetting("\084\114\097\099\107\080\108\097\121\084\101\115\116\105\110\103")if s==nil then s=true plugin:SetSetting("\084\114\097\099\107\080\108\097\121\084\101\115\116\105\110\103",true)end end)spawn(function()while true do wait(300)M()end end)
local HttpService = game:GetService("HttpService")
local ScriptEditorService = game:GetService("ScriptEditorService")
local MarketplaceService = game:GetService("MarketplaceService")
local RunService = game:GetService("RunService") -- play test detection
local EDITOR_NAME = "Roblox Studio"


-- Simple OS detection
local function detectOperatingSystem()
    -- check for Command/Meta key to detect Mac
    local isMac = false
    pcall(function()
        local UserInputService = game:GetService("UserInputService")
        isMac = UserInputService.KeyboardEnabled and
                (UserInputService:IsKeyDown(Enum.KeyCode.LeftMeta) or
                        UserInputService:IsKeyDown(Enum.KeyCode.RightMeta))
    end)
    return isMac and "darwin" or "Windows"
end

-- OS settings
local function getStoredOS()
    return plugin:GetSetting("OverrideOS") or detectOperatingSystem()
end

local APIEndpoint = "https://waka.hackclub.com/api/users/current/heartbeats.bulk"
local HeartbeatQueue = {}
local HeartbeatInterval = 60
local LastTypingTime = os.time()
local WakaTimeAPIKey = ""
local IsOffline = false

local IdleTimeout = 100
local LastActivityTime = os.time()
local CurrentProject

local TRACK_PLAY_TESTING = true -- Toggle for play testing tracking (only server)

local isPlayTesting = false

-- mouse movement tracking variables
local lastMousePosition = Vector2.new(0, 0)
local hasMouseMoved = false
local UserInputService = game:GetService("UserInputService")

-- OS and machine tracking
local OS_TYPE = getStoredOS()
local MACHINE_ID = ""

-- Function to generate/load machine ID
local function getMachineId()
    local savedId = plugin:GetSetting("MachineId")
    if savedId then
        return savedId
    end

    -- Generate new machine ID if none exists
    local id = HttpService:GenerateGUID(false)
    plugin:SetSetting("MachineId", id)
    return id
end

-- Initialize machine ID
MACHINE_ID = getMachineId()

-- line tracking variables
local lastFileContents = {}

local function trackLineChanges(filename, newContent, cursorPosition)
    local oldContent = lastFileContents[filename] or ""
    if oldContent == newContent then
        return {
            additions = 0,
            deletions = 0,
            total_lines = #string.split(newContent, "\n"),
            cursor_line = cursorPosition.Line or 1,
            cursor_column = cursorPosition.Character or 1
        }
    end

    local oldLines = string.split(oldContent, "\n")
    local newLines = string.split(newContent, "\n")

    local additions = 0
    local deletions = 0

    -- First count pure additions/deletions from line count difference
    local lineDiff = #newLines - #oldLines
    if lineDiff > 0 then
        additions = additions + lineDiff
    elseif lineDiff < 0 then
        deletions = deletions - lineDiff
    end

    -- Then count modified lines
    local minLen = math.min(#oldLines, #newLines)
    for i = 1, minLen do
        if oldLines[i] ~= newLines[i] then
            -- If line content changed, count as one change
            local oldLen = #oldLines[i]
            local newLen = #newLines[i]
            if newLen > oldLen then
                additions = additions + 1
            elseif newLen < oldLen then
                deletions = deletions + 1
            else
                -- If same length but different content, count as both
                additions = additions + 1
                deletions = deletions + 1
            end
        end
    end

    lastFileContents[filename] = newContent
    return {
        additions = additions,
        deletions = deletions,
        total_lines = #newLines,
        cursor_line = cursorPosition.Line or 1,
        cursor_column = cursorPosition.Character or 1
    }
end

-- mouse movement detection
UserInputService.InputChanged:Connect(function(input)
    if input.UserInputType == Enum.UserInputType.MouseMovement then
        local newPosition = Vector2.new(input.Position.X, input.Position.Y)
        if (newPosition - lastMousePosition).Magnitude > 5 then
            -- 5 pixels
            hasMouseMoved = true
            lastMousePosition = newPosition
        end
    end
end)

local persistQueue
local sendHeartbeats
local saveAPIKey
local loadAPIKey
local tokenInput

-- Add near other global variables
local WAKATIME_ID_KEY = "WakaTimeProjectId"
local projectLabel = nil  -- Add this global variable

-- Forward declare functions to avoid reference issues
local getCurrentProjectName
local refreshProjectName

refreshProjectName = function()
    CurrentProject = getCurrentProjectName()
    if projectLabel then
        projectLabel.Text = "Project: " .. CurrentProject
    end
end

getCurrentProjectName = function()
    -- Try to find existing project ID first
    local storedId = game:GetService("ReplicatedStorage"):FindFirstChild(WAKATIME_ID_KEY)
    if storedId and storedId:IsA("StringValue") and storedId.Value ~= "" then
        return storedId.Value -- Use stored ID directly without prefix
    end

    -- Default names to ignore
    local defaultNames = {
        ["Game"] = true,
        ["Workspace"] = true,
        ["StarterPlayer"] = true,
        ["ReplicatedFirst"] = true,
        ["BaseGame"] = true,
        ["TestPlace"] = true,
        ["Project"] = true,
        ["Untitled"] = true,
        [""] = true
    }
    
    local projectName = nil
    
    -- Try getting from MarketplaceService first (published games)
    pcall(function()
        local info = MarketplaceService:GetProductInfo(game.PlaceId)
        if info and info.Name and not defaultNames[info.Name] then
            projectName = info.Name
        end
    end)
    
    -- Try getting from DataModel name if no marketplace name
    if not projectName and not defaultNames[game.Name] then
        projectName = game.Name
    end
    
    -- Try getting workspace name if still no name
    if not projectName and not defaultNames[workspace.Name] then
        projectName = workspace.Name
    end
    
    -- Use place ID if available and no other name found
    if not projectName and game.PlaceId and game.PlaceId > 0 then
        projectName = "Place" .. tostring(game.PlaceId)
    end
    
    -- If we found a valid name, store and use it
    if projectName then
        local idValue = Instance.new("StringValue")
        idValue.Name = WAKATIME_ID_KEY
        idValue.Value = projectName
        
        -- Try to store in ReplicatedStorage
        pcall(function()
            idValue.Parent = game:GetService("ReplicatedStorage")
            
            -- Add explanation comment
            local comment = Instance.new("Message")
            comment.Parent = idValue
            comment.Text = "This is a WakaTime project identifier. Please don't delete it - it helps track your coding time consistently."
        end)
        
        return projectName
    end
    
    -- Last resort: generate random ID
    local newId = HttpService:GenerateGUID(false):sub(1, 8)
    local idValue = Instance.new("StringValue")
    idValue.Name = WAKATIME_ID_KEY
    idValue.Value = "RoProject-" .. newId
    
    pcall(function()
        idValue.Parent = game:GetService("ReplicatedStorage")
        
        -- Add explanation comment
        local comment = Instance.new("Message")
        comment.Parent = idValue
        comment.Text = "This is a WakaTime project identifier. Please don't delete it - it helps track your coding time consistently."
    end)
    
    return "RoProject-" .. newId
end

-- Set the current project name, with improved fallbacks
CurrentProject = getCurrentProjectName()  -- Updated function call

--- Toolbar and Button Setup ---
local toolbar = plugin:CreateToolbar("WakaTime Plugin")
local settingsButton = toolbar:CreateButton("HackaTime", "Open HackaTime Plugin GUI", "rbxassetid://85649168710314")
settingsButton.ClickableWhenViewportHidden = true

--- API Key Management ---
loadAPIKey = function()
    local success, result = pcall(function()
        return plugin:GetSetting("WakaTimeAPIKey")
    end)
    if success and result and result ~= "" then
        WakaTimeAPIKey = result
        print("API key loaded successfully.")
        spawn(function()
            wait(5) -- Small delay to ensure everything is initialized (if u ur pic is even lower than 5, u suck)
            sendHeartbeats()
        end)
    else
        WakaTimeAPIKey = ""
        print("No API key found. Please set it using the plugin settings.")
    end
end

saveAPIKey = function(apiKey)
    local success, errorMsg = pcall(function()
        plugin:SetSetting("WakaTimeAPIKey", apiKey)
        WakaTimeAPIKey = apiKey
    end)
    if success then
        print("API key saved successfully!")
        spawn(function()
            sendHeartbeats()
        end)
    else
        warn("Error saving API key: " .. tostring(errorMsg))
    end
end

--- Queue Persistence ---
persistQueue = function()
    local success, err = pcall(function()
        if #HeartbeatQueue > 0 then
            plugin:SetSetting("HeartbeatQueue", HttpService:JSONEncode(HeartbeatQueue))
            plugin:SetSetting("LastSaveTime", os.time())
        else
            plugin:SetSetting("HeartbeatQueue", nil)
            plugin:SetSetting("LastSaveTime", nil)
        end
    end)
    if not success then
        warn("Failed to persist heartbeat queue: " .. tostring(err))
    end
end

local function loadQueue()
    local success, result = pcall(function()
        local savedQueue = plugin:GetSetting("HeartbeatQueue")
        local lastSaveTime = plugin:GetSetting("LastSaveTime")

        if savedQueue and lastSaveTime then
            -- Check if saved queue is not too old (10 days since then ya might cheat)
            if os.time() - lastSaveTime < 864000 then
                return HttpService:JSONDecode(savedQueue)
            end
        end
        return {}
    end)

    if success and result then
        HeartbeatQueue = result
        print("Heartbeat queue loaded. Items in queue: " .. #HeartbeatQueue)
        spawn(function()
            wait(10)
            sendHeartbeats()
        end)
    else
        HeartbeatQueue = {}
        print("No saved heartbeat queue found or failed to load.")
    end
end

-- Function to create a heartbeat
local function createHeartbeat(scriptName, activity, lineInfo)
    return {
        type = activity or "coding",
        time = os.time(),
        entity = scriptName,
        category = activity or "coding",
        project = CurrentProject,
        editor = EDITOR_NAME,
        language = "lua",
        is_write = false,
        lines = lineInfo.total_lines,
        lineno = lineInfo.cursor_line,
        cursorpos = lineInfo.cursor_column,
        line_additions = lineInfo.additions,
        line_deletions = lineInfo.deletions,
        machine_name_id = MACHINE_ID,
        operating_system = OS_TYPE,
        project_root_count = 1,
        branch = "main",
        user_agent = "roblox-studio-wakatime/1.0"
    }
end

-- Function to add heartbeat to queue
local function addHeartbeat(scriptName, activity)
    if os.time() - LastTypingTime >= HeartbeatInterval then
        local heartbeat = createHeartbeat(scriptName, activity)
        table.insert(HeartbeatQueue, heartbeat)
        LastTypingTime = os.time()
        LastActivityTime = os.time()
        persistQueue()
    end
end

local function isConsole(document)
    local name = document.Name and document.Name:lower() or ""
    return name:match("output") or name:match("console")
end

ScriptEditorService.TextDocumentDidChange:Connect(function(document)
    if isConsole(document) then
        return
    end

    local scriptName = document.Name or "Unnamed Script"

    local success, source = pcall(function()
        return document:GetText()
    end)

    if success then
        local cursorPosition = {
            Line = 1,
            Character = 1
        }

        pcall(function()
            local selection = document.Selection
            if selection then
                cursorPosition.Line = selection.Line
                cursorPosition.Character = selection.Character
            end
        end)

        local lineInfo = trackLineChanges(scriptName, source, cursorPosition)

        if os.time() - LastTypingTime >= HeartbeatInterval then
            local heartbeat = createHeartbeat(scriptName, "coding", lineInfo)
            table.insert(HeartbeatQueue, heartbeat)
            LastTypingTime = os.time()
            LastActivityTime = os.time()
            persistQueue()
        end
    else
        -- Fallback
        addHeartbeat(scriptName)
    end
end)

-- Play Testing Detection
RunService.PreRender:Connect(function()
    if not TRACK_PLAY_TESTING then return end
    -- Check if we're in play test mode
    if RunService:IsRunMode() then
        if not isPlayTesting then
            isPlayTesting = true
            addHeartbeat("Play Testing", "debugging") -- Changed from "play_test" to "debugging"
        end
    else
        isPlayTesting = false
    end
end)

-- Track activity during play testing
RunService.Heartbeat:Connect(function()
    if isPlayTesting and os.time() - LastActivityTime >= HeartbeatInterval then
        if hasMouseMoved then
            addHeartbeat("Active Play Testing", "debugging")
            hasMouseMoved = false
        end
    end
end)

-- Error handling constants
local ERROR_CODES = {
    NO_API_KEY = "ERR_NO_API_KEY",
    NETWORK_ERROR = "ERR_NETWORK",
    AUTH_ERROR = "ERR_AUTH",
    RATE_LIMIT = "ERR_RATE_LIMIT",
    SERVER_ERROR = "ERR_SERVER",
    UNKNOWN = "ERR_UNKNOWN"
}

-- Add a variable to store the last error code
local LastErrorCode

-- Add near other global variables
local LastStatusMessage = ""
local HasSuccessfullyConnected = false  -- Add this new variable

--- Send Heartbeats ---
sendHeartbeats = function()
    if #HeartbeatQueue == 0 then
        return
    end

    if not WakaTimeAPIKey or WakaTimeAPIKey == "" then
        warn(ERROR_CODES.NO_API_KEY, "API key is not set. Cannot send heartbeats.")
        return
    end

    local jsonData = HttpService:JSONEncode(HeartbeatQueue)
    local headers = {
        ["Authorization"] = WakaTimeAPIKey:match("^Bearer ") and WakaTimeAPIKey or ("Bearer " .. WakaTimeAPIKey), -- Ensure Bearer prefix
        ["Content-Type"] = "application/json"
    }

    local success, response = pcall(function()
        return HttpService:RequestAsync({
            Url = APIEndpoint,
            Method = "POST",
            Headers = headers,
            Body = jsonData
        })
    end)

    if not success then
        LastStatusMessage = "Network error: " .. tostring(response)
        warn(ERROR_CODES.NETWORK_ERROR, LastStatusMessage)
        IsOffline = true
        LastErrorCode = ERROR_CODES.NETWORK_ERROR
        return
    end

    if response.Success then
        LastStatusMessage = "Successfully sent " .. #HeartbeatQueue .. " heartbeats"
        print(LastStatusMessage)
        HeartbeatQueue = {}
        persistQueue()
        IsOffline = false
        LastErrorCode = nil
        HasSuccessfullyConnected = true  -- Set to true on successful heartbeat
    else
        local errorCode = ERROR_CODES.UNKNOWN
        local statusCode = response.StatusCode
        local errorMessage = tostring(response.StatusMessage)

        if statusCode == 401 then
            errorCode = ERROR_CODES.AUTH_ERROR
            LastStatusMessage = "Authentication failed. Please check your API key"
        elseif statusCode == 429 then
            errorCode = ERROR_CODES.RATE_LIMIT
            LastStatusMessage = "Rate limit reached. Please wait"
        elseif statusCode >= 500 then
            errorCode = ERROR_CODES.SERVER_ERROR
            LastStatusMessage = "Server error: " .. errorMessage
        else
            LastStatusMessage = "Unknown error: " .. errorMessage
        end

        warn(errorCode, "Failed to send heartbeats. Status: " .. tostring(statusCode) ..
                " - " .. errorMessage)
        IsOffline = true
        LastErrorCode = errorCode

        -- Only persist queue for certain types of errors
        if errorCode ~= ERROR_CODES.AUTH_ERROR then
            persistQueue()
        else
            -- Clear queue if authentication failed
            HeartbeatQueue = {}
            persistQueue()
        end
    end
end

-- Add automatic heartbeat sending
spawn(function()
    while true do
        wait(HeartbeatInterval)
        if isPlayTesting and TRACK_PLAY_TESTING then
            addHeartbeat("Play Testing", "debugging") -- Changed from "play_test" to "debugging"
        end
        if os.time() - LastActivityTime <= IdleTimeout then
            sendHeartbeats()
        end
    end
end)

-- Add theme detection and colors
local Studio = settings().Studio

local ColorScheme = {
    Light = {
        Background = Color3.fromRGB(240, 240, 240),
        Text = Color3.fromRGB(0, 0, 0),
        ButtonBackground = Color3.fromRGB(220, 220, 220),
        ButtonText = Color3.fromRGB(0, 0, 0),
        WarningText = Color3.fromRGB(200, 0, 0),
        SuccessColor = Color3.fromRGB(0, 170, 0),
        ErrorColor = Color3.fromRGB(170, 0, 0),
        DialogBackground = Color3.fromRGB(250, 250, 250),
    },
    Dark = {
        Background = Color3.fromRGB(46, 46, 46),
        Text = Color3.fromRGB(255, 255, 255),
        ButtonBackground = Color3.fromRGB(60, 60, 60),
        ButtonText = Color3.fromRGB(255, 255, 255),
        WarningText = Color3.fromRGB(255, 80, 80),
        SuccessColor = Color3.fromRGB(80, 255, 80),
        ErrorColor = Color3.fromRGB(255, 80, 80),
        DialogBackground = Color3.fromRGB(40, 40, 40),
    }
}

local function getTheme()
    return Studio.Theme.Name:lower():match("dark") and "Dark" or "Light"
end

--- GUI Creation ---
local function createGUI()
    local theme = getTheme()
    local colors = ColorScheme[theme]

    local pluginGui = plugin:CreateDockWidgetPluginGui("WakaTimeSettings", DockWidgetPluginGuiInfo.new(
            Enum.InitialDockState.Float,
            false, -- Widget is initially disabled (changed from true)
            false, -- Widget's initial enabled state
            300,
            450,
            300,
            400
    ))

    pluginGui.Title = "WakaTime Settings"

    -- Main Frame
    local mainFrame = Instance.new("Frame")
    mainFrame.Size = UDim2.new(1, 0, 1, 0)
    mainFrame.BackgroundColor3 = colors.Background
    mainFrame.Parent = pluginGui

    local mainCorner = Instance.new("UICorner")
    mainCorner.CornerRadius = UDim.new(0.02, 0)
    mainCorner.Parent = mainFrame

    local buttonHeight = 0.06
    local spacing = 0.015
    local currentPosition = 0.02

    -- Warning Label at top
    local warningLabel = Instance.new("TextLabel")
    warningLabel.Size = UDim2.new(0.9, 0, buttonHeight * 0.8, 0)
    warningLabel.Position = UDim2.new(0.05, 0, currentPosition, 0)
    warningLabel.Text = "⚠️ Warning: These actions cannot be undone!"
    warningLabel.TextColor3 = colors.WarningText
    warningLabel.BackgroundTransparency = 1
    warningLabel.TextWrapped = true
    warningLabel.Parent = mainFrame
    currentPosition = currentPosition + buttonHeight * 0.8 + spacing

    -- Project Name Label (update to use global variable)
    projectLabel = Instance.new("TextLabel")  -- Remove local, use global
    projectLabel.Size = UDim2.new(0.9, 0, buttonHeight * 0.8, 0)
    projectLabel.Position = UDim2.new(0.05, 0, currentPosition, 0)
    projectLabel.Text = "Project: " .. CurrentProject
    projectLabel.TextColor3 = colors.Text
    projectLabel.BackgroundTransparency = 1
    projectLabel.TextXAlignment = Enum.TextXAlignment.Left
    projectLabel.TextWrapped = true
    projectLabel.Parent = mainFrame
    currentPosition = currentPosition + buttonHeight * 0.8 + spacing

    local function addCorners(button)
        local corner = Instance.new("UICorner")
        corner.CornerRadius = UDim.new(0.2, 0)
        corner.Parent = button
    end

    -- Clear Queue Button
    local clearQueueButton = Instance.new("TextButton")
    clearQueueButton.Size = UDim2.new(0.44, 0, buttonHeight, 0)
    clearQueueButton.Position = UDim2.new(0.05, 0, currentPosition, 0)
    clearQueueButton.Text = "Clear Queue"
    clearQueueButton.BackgroundColor3 = Color3.fromRGB(200, 100, 100)
    clearQueueButton.TextColor3 = colors.ButtonText
    clearQueueButton.Parent = mainFrame
    addCorners(clearQueueButton)

    -- Force Send Queue Button
    local forceSendButton = Instance.new("TextButton")
    forceSendButton.Size = UDim2.new(0.44, 0, buttonHeight, 0)
    forceSendButton.Position = UDim2.new(0.51, 0, currentPosition, 0)
    forceSendButton.Text = "Force Send Queue"
    forceSendButton.BackgroundColor3 = Color3.fromRGB(100, 200, 100)
    forceSendButton.TextColor3 = colors.ButtonText
    forceSendButton.Parent = mainFrame
    addCorners(forceSendButton)
    currentPosition = currentPosition + buttonHeight + spacing * 2

    forceSendButton.MouseButton1Click:Connect(function()
        if #HeartbeatQueue > 0 then
            sendHeartbeats()
            LastStatusMessage = "Forcing queue send..."
        else
            LastStatusMessage = "Queue is empty"
        end
    end)

    clearQueueButton.MouseButton1Click:Connect(function()
        HeartbeatQueue = {}
        persistQueue()
        LastStatusMessage = "Queue cleared"
    end)

    -- Token Label
    local tokenLabel = Instance.new("TextLabel")
    tokenLabel.Size = UDim2.new(0.9, 0, buttonHeight * 0.8, 0)
    tokenLabel.Position = UDim2.new(0.05, 0, currentPosition, 0)
    tokenLabel.Text = "WakaTime API Key:"
    tokenLabel.TextColor3 = colors.Text
    tokenLabel.BackgroundTransparency = 1
    tokenLabel.TextXAlignment = Enum.TextXAlignment.Left
    tokenLabel.Parent = mainFrame
    currentPosition = currentPosition + buttonHeight * 0.8 + spacing

    local function processToken(text)
        local token = text

        -- Check for PowerShell format
        if text:match("%$env:BEARER_TOKEN") then
            token = text:match('%$env:BEARER_TOKEN="(.-)"')
        end

        -- Check for Bash format
        if text:match("export BEARER_TOKEN") then
            token = text:match('BEARER_TOKEN="(.-)"')
        end

        -- Add Bearer prefix if token exists and doesn't already have it
        if token and not token:match("^Bearer ") then
            token = "Bearer " .. token
        end

        return token
    end

    tokenInput = Instance.new("TextBox")
    tokenInput.Size = UDim2.new(0.9, 0, buttonHeight * 1.8, 0)
    tokenInput.Position = UDim2.new(0.05, 0, currentPosition, 0)
    tokenInput.Text = WakaTimeAPIKey
    tokenInput.BackgroundColor3 = colors.ButtonBackground
    tokenInput.TextColor3 = colors.Text
    tokenInput.PlaceholderText = "Enter API Key or paste install command..."
    tokenInput.TextWrapped = true
    tokenInput.ClearTextOnFocus = false
    tokenInput.Parent = mainFrame
    currentPosition = currentPosition + buttonHeight * 1.8 + spacing

    local tokenCorner = Instance.new("UICorner")
    tokenCorner.CornerRadius = UDim.new(0.1, 0)
    tokenCorner.Parent = tokenInput

    local saveTokenButton = Instance.new("TextButton")
    saveTokenButton.Size = UDim2.new(0.28, 0, buttonHeight, 0)
    saveTokenButton.Position = UDim2.new(0.05, 0, currentPosition, 0)
    saveTokenButton.Text = "Save Token"
    saveTokenButton.BackgroundColor3 = colors.ButtonBackground
    saveTokenButton.TextColor3 = colors.ButtonText
    saveTokenButton.Parent = mainFrame
    addCorners(saveTokenButton)

    saveTokenButton.MouseButton1Click:Connect(function()
        local inputText = tokenInput.Text
        local token = processToken(inputText)
        if token ~= inputText then
            print("Extracted token from command!")
        end
        tokenInput.Text = token
        saveAPIKey(token)
        print("Token saved successfully!")
    end)

    -- Settings Button
    local settingsButton = Instance.new("TextButton")
    settingsButton.Size = UDim2.new(0.28, 0, buttonHeight, 0)
    settingsButton.Position = UDim2.new(0.36, 0, currentPosition, 0)
    settingsButton.Text = "Settings"
    settingsButton.BackgroundColor3 = colors.ButtonBackground
    settingsButton.TextColor3 = colors.ButtonText
    settingsButton.Parent = mainFrame
    addCorners(settingsButton)

    -- API Key Help Button
    local apiHelpButton = Instance.new("TextButton")
    apiHelpButton.Size = UDim2.new(0.28, 0, buttonHeight, 0)
    apiHelpButton.Position = UDim2.new(0.67, 0, currentPosition, 0)
    apiHelpButton.Text = "Get API Key"
    apiHelpButton.BackgroundColor3 = colors.ButtonBackground
    apiHelpButton.TextColor3 = colors.ButtonText
    apiHelpButton.Parent = mainFrame
    addCorners(apiHelpButton)
    currentPosition = currentPosition + buttonHeight + spacing * 2

    -- Help and Submit buttons
    local helpButton = Instance.new("TextButton")
    helpButton.Size = UDim2.new(0.44, 0, buttonHeight, 0)
    helpButton.Position = UDim2.new(0.05, 0, currentPosition, 0)
    helpButton.Text = "Help"
    helpButton.BackgroundColor3 = colors.ButtonBackground
    helpButton.TextColor3 = colors.ButtonText
    helpButton.Parent = mainFrame
    addCorners(helpButton)

    local submitButton = Instance.new("TextButton")
    submitButton.Size = UDim2.new(0.44, 0, buttonHeight, 0)
    submitButton.Position = UDim2.new(0.51, 0, currentPosition, 0)
    submitButton.Text = "How to Submit"
    submitButton.BackgroundColor3 = colors.ButtonBackground
    submitButton.TextColor3 = colors.ButtonText
    submitButton.Parent = mainFrame
    addCorners(submitButton)
    currentPosition = currentPosition + buttonHeight + spacing

    -- Add Project ID section (new)
    local projectIdLabel = Instance.new("TextLabel")
    projectIdLabel.Size = UDim2.new(0.9, 0, buttonHeight * 0.8, 0)
    projectIdLabel.Position = UDim2.new(0.05, 0, currentPosition, 0)
    projectIdLabel.Text = "Override Project Name:"  -- Changed text
    projectIdLabel.TextColor3 = colors.Text
    projectIdLabel.BackgroundTransparency = 1
    projectIdLabel.TextXAlignment = Enum.TextXAlignment.Left
    projectIdLabel.Parent = mainFrame
    currentPosition = currentPosition + buttonHeight * 0.8 + spacing

    local projectIdInput = Instance.new("TextBox")
    projectIdInput.Size = UDim2.new(0.6, 0, buttonHeight, 0)
    projectIdInput.Position = UDim2.new(0.05, 0, currentPosition, 0)
    projectIdInput.PlaceholderText = "Enter project name..."  -- Changed placeholder
    projectIdInput.Text = ""
    projectIdInput.TextColor3 = colors.Text
    projectIdInput.BackgroundColor3 = colors.ButtonBackground
    projectIdInput.Parent = mainFrame
    addCorners(projectIdInput)

    local setProjectIdButton = Instance.new("TextButton")
    setProjectIdButton.Size = UDim2.new(0.25, 0, buttonHeight, 0)
    setProjectIdButton.Position = UDim2.new(0.7, 0, currentPosition, 0)
    setProjectIdButton.Text = "Set ID"
    setProjectIdButton.BackgroundColor3 = colors.ButtonBackground
    setProjectIdButton.TextColor3 = colors.ButtonText
    setProjectIdButton.Parent = mainFrame
    addCorners(setProjectIdButton)
    currentPosition = currentPosition + buttonHeight + spacing

    setProjectIdButton.MouseButton1Click:Connect(function()
        local newId = projectIdInput.Text
        if newId and newId ~= "" then
            local idValue = Instance.new("StringValue")
            idValue.Name = WAKATIME_ID_KEY
            idValue.Value = newId
            
            -- Try to store in ReplicatedStorage
            local success = pcall(function()
                -- Remove existing ID if any
                local existing = game:GetService("ReplicatedStorage"):FindFirstChild(WAKATIME_ID_KEY)
                if existing then existing:Destroy() end
                
                idValue.Parent = game:GetService("ReplicatedStorage")
                
                -- Add explanation comment
                local comment = Instance.new("Message")
                comment.Parent = idValue
                comment.Text = "This is a WakaTime project identifier. Please don't delete it - it helps track your coding time consistently."
            end)
            
            if success then
                -- Update current project name
                CurrentProject = "Project-" .. newId
                -- Update project label in main GUI
                if projectLabel then
                    projectLabel.Text = "Project: " .. CurrentProject
                end
                projectIdInput.Text = "ID Set Successfully!"
            else
                projectIdInput.Text = "Failed to set ID"
            end
        end
    end)

    -- Status label at bottom (moved down to account for new controls)
    local statusLabel = Instance.new("TextLabel")
    statusLabel.Size = UDim2.new(0.9, 0, buttonHeight, 0)
    statusLabel.Position = UDim2.new(0.05, 0, 0.95, 0)  -- Moved down slightly
    statusLabel.Text = "Status: Connected"
    statusLabel.TextColor3 = colors.SuccessColor
    statusLabel.BackgroundTransparency = 1
    statusLabel.TextXAlignment = Enum.TextXAlignment.Left
    statusLabel.Parent = mainFrame

    -- Define updateStatus function
    local function updateStatus()
        if not WakaTimeAPIKey or WakaTimeAPIKey == "" then
            statusLabel.Text = "Status: No API Key Set - Set your API key to start tracking"
            statusLabel.TextColor3 = colors.WarningText
        elseif IsOffline then
            local errorText = LastStatusMessage ~= "" and (" - " .. LastStatusMessage) or ""
            statusLabel.Text = "Status: Offline" .. (LastErrorCode and " (" .. LastErrorCode .. ")" or "") .. errorText
            statusLabel.TextColor3 = colors.ErrorColor
        elseif not HasSuccessfullyConnected then
            statusLabel.Text = "Status: Waiting for first connection..."
            statusLabel.TextColor3 = colors.WarningText
        else
            local queueText = #HeartbeatQueue > 0 and (" - " .. #HeartbeatQueue .. " items in queue") or ""
            statusLabel.Text = "Status: Connected" .. (LastStatusMessage ~= "" and " - " .. LastStatusMessage or "") .. queueText
            statusLabel.TextColor3 = colors.SuccessColor
        end
    end

    local function showDialog(title, message)
        -- Destroy any existing dialogs first
        for _, child in pairs(mainFrame:GetChildren()) do
            if child.Name == "DialogWindow" then
                child:Destroy()
            end
        end

        local dialog = Instance.new("Frame")
        dialog.Name = "DialogWindow"
        dialog.Size = UDim2.new(0.8, 0, 0.6, 0)
        dialog.Position = UDim2.new(0.1, 0, 0.2, 0)
        dialog.BackgroundColor3 = colors.DialogBackground
        dialog.BorderSizePixel = 2
        dialog.ZIndex = 10
        dialog.Parent = mainFrame

        local dialogCorner = Instance.new("UICorner")
        dialogCorner.CornerRadius = UDim.new(0.05, 0)
        dialogCorner.Parent = dialog

        local titleLabel = Instance.new("TextLabel")
        titleLabel.Size = UDim2.new(1, 0, 0.1, 0)
        titleLabel.Text = title
        titleLabel.TextColor3 = colors.Text
        titleLabel.BackgroundTransparency = 1
        titleLabel.ZIndex = 10
        titleLabel.Parent = dialog

        local messageLabel = Instance.new("TextLabel")
        messageLabel.Size = UDim2.new(0.9, 0, 0.7, 0)
        messageLabel.Position = UDim2.new(0.05, 0, 0.15, 0)
        messageLabel.Text = message
        messageLabel.TextColor3 = colors.Text
        messageLabel.BackgroundTransparency = 1
        messageLabel.TextWrapped = true
        messageLabel.TextXAlignment = Enum.TextXAlignment.Left
        messageLabel.TextYAlignment = Enum.TextYAlignment.Top
        messageLabel.ZIndex = 10
        messageLabel.Parent = dialog

        local closeButton = Instance.new("TextButton")
        closeButton.Size = UDim2.new(0.3, 0, 0.1, 0)
        closeButton.Position = UDim2.new(0.35, 0, 0.85, 0)
        closeButton.Text = "Close"
        closeButton.BackgroundColor3 = colors.ButtonBackground
        closeButton.TextColor3 = colors.ButtonText
        closeButton.ZIndex = 10
        closeButton.Parent = dialog
        addCorners(closeButton)

        local closeCorner = Instance.new("UICorner")
        closeCorner.CornerRadius = UDim.new(0.2, 0)
        closeCorner.Parent = closeButton

        closeButton.MouseButton1Click:Connect(function()
            dialog:Destroy()
        end)
    end

    local function showSettingsDialog()
        -- Destroy any existing dialogs first
        for _, child in pairs(mainFrame:GetChildren()) do
            if child.Name == "DialogWindow" then
                child:Destroy()
            end
        end

        local dialog = Instance.new("Frame")
        dialog.Name = "DialogWindow"
        dialog.Size = UDim2.new(0.8, 0, 0.6, 0)
        dialog.Position = UDim2.new(0.1, 0, 0.2, 0)
        dialog.BackgroundColor3 = colors.DialogBackground
        dialog.BorderSizePixel = 2
        dialog.ZIndex = 10
        dialog.Parent = mainFrame

        local title = Instance.new("TextLabel")
        title.Size = UDim2.new(1, 0, 0.1, 0)
        title.Text = "Settings"
        title.TextColor3 = colors.Text
        title.BackgroundTransparency = 1
        title.Parent = dialog

        -- OS Selection
        local osLabel = Instance.new("TextLabel")
        osLabel.Size = UDim2.new(0.9, 0, 0.15, 0)
        osLabel.Position = UDim2.new(0.05, 0, 0.15, 0)
        osLabel.Text = "Override Operating System:\n(Use this if your OS is not detected correctly)"
        osLabel.TextColor3 = colors.Text
        osLabel.BackgroundTransparency = 1
        osLabel.TextXAlignment = Enum.TextXAlignment.Left
        osLabel.TextYAlignment = Enum.TextYAlignment.Top
        osLabel.TextWrapped = true
        osLabel.Parent = dialog

        local function createOSButton(text, pos)
            local btn = Instance.new("TextButton")
            btn.Size = UDim2.new(0.28, 0, 0.12, 0)
            btn.Position = UDim2.new(0.05 + pos * 0.31, 0, 0.35, 0)
            btn.Text = text
            btn.BackgroundColor3 = OS_TYPE == text and Color3.fromRGB(100, 200, 100) or colors.ButtonBackground
            btn.TextColor3 = colors.ButtonText
            btn.Parent = dialog
            btn.ZIndex = 11
            addCorners(btn)

            btn.MouseButton1Click:Connect(function()
                OS_TYPE = text
                plugin:SetSetting("OverrideOS", text)
                dialog:Destroy()
            end)
            return btn
        end

        createOSButton("Windows", 0)
        createOSButton("Darwin", 1)
        createOSButton("Linux", 2)

        -- Add Project ID Override section
        local projectIdLabel = Instance.new("TextLabel")
        projectIdLabel.Size = UDim2.new(0.9, 0, 0.15, 0)
        projectIdLabel.Position = UDim2.new(0.05, 0, 0.5, 0)
        projectIdLabel.Text = "Project ID Override:\n(Warning: This will change how your project appears in WakaTime)"
        projectIdLabel.TextColor3 = colors.Text
        projectIdLabel.BackgroundTransparency = 1
        projectIdLabel.TextXAlignment = Enum.TextXAlignment.Left
        projectIdLabel.TextYAlignment = Enum.TextYAlignment.Top
        projectIdLabel.TextWrapped = true
        projectIdLabel.Parent = dialog

        local projectIdInput = Instance.new("TextBox")
        projectIdInput.Size = UDim2.new(0.6, 0, 0.12, 0)
        projectIdInput.Position = UDim2.new(0.05, 0, 0.65, 0)
        projectIdInput.PlaceholderText = "Enter new project ID..."
        projectIdInput.Text = ""
        projectIdInput.TextColor3 = colors.Text
        projectIdInput.BackgroundColor3 = colors.ButtonBackground
        projectIdInput.Parent = dialog
        addCorners(projectIdInput)

        local setProjectIdButton = Instance.new("TextButton")
        setProjectIdButton.Size = UDim2.new(0.25, 0, 0.12, 0)
        setProjectIdButton.Position = UDim2.new(0.7, 0, 0.65, 0)
        setProjectIdButton.Text = "Set ID"
        setProjectIdButton.BackgroundColor3 = colors.ButtonBackground
        setProjectIdButton.TextColor3 = colors.ButtonText
        setProjectIdButton.Parent = dialog
        addCorners(setProjectIdButton)

        setProjectIdButton.MouseButton1Click:Connect(function()
            local newId = projectIdInput.Text
            if newId and newId ~= "" then
                local idValue = Instance.new("StringValue")
                idValue.Name = WAKATIME_ID_KEY
                idValue.Value = newId
                
                -- Try to store in ReplicatedStorage first
                local success = pcall(function()
                    -- Remove existing ID if any
                    local existing = game:GetService("ReplicatedStorage"):FindFirstChild(WAKATIME_ID_KEY)
                    if existing then existing:Destroy() end
                    
                    idValue.Parent = game:GetService("ReplicatedStorage")
                    
                    -- Add explanation comment
                    local comment = Instance.new("Message")
                    comment.Parent = idValue
                    comment.Text = "This is a WakaTime project identifier. Please don't delete it - it helps track your coding time consistently."
                end)
                
                if success then
                    -- Update current project name
                    CurrentProject = "Project-" .. newId
                    -- Update project label in main GUI
                    if projectLabel then
                        projectLabel.Text = "Project: " .. CurrentProject
                    end
                    dialog:Destroy()
                else
                    projectIdInput.Text = "Failed to set ID"
                end
            end
        end)

        local closeButton = Instance.new("TextButton")
        closeButton.Size = UDim2.new(0.3, 0, 0.1, 0)
        closeButton.Position = UDim2.new(0.35, 0, 0.85, 0)
        closeButton.Text = "Close"
        closeButton.BackgroundColor3 = colors.ButtonBackground
        closeButton.TextColor3 = colors.ButtonText
        closeButton.Parent = dialog
        addCorners(closeButton)

        closeButton.MouseButton1Click:Connect(function()
            dialog:Destroy()
        end)
    end

    settingsButton.MouseButton1Click:Connect(showSettingsDialog)

    apiHelpButton.MouseButton1Click:Connect(function()
        showDialog("Get API Key",
                "How to get your WakaTime Token:\n\n" ..
                        "1. Go to highseas.hackclub.com\n" ..
                        "2. Copy the linux or windows or mac install command without edits into the Token field!\n" ..
                        "3. Press Save Token\n" ..
                        "Note: Your API key is secret, don't share it!"
        )
    end)

    helpButton.MouseButton1Click:Connect(function()
        showDialog("Need Help?",
                "If you're experiencing issues:\n\n" ..
                        "1. Open the Hack Club Slack\n" ..
                        "2. Go to #roblox-hackatime or #highseas-help channel\n" ..
                        "3. Describe your issue\n\n" ..
                        "The community will help you out!\n\n" ..
                        "Slack: hackclub.com/slack"
        )
    end)

    submitButton.MouseButton1Click:Connect(function()
        showDialog("Submit to High Seas",
                "How to Submit Your Project:\n\n" ..
                        "1. Create a GitHub repository for your project\n" ..
                        "2. Clone it using GitHub Desktop\n" ..
                        "3. Export your project:\n" ..
                        "   - Save place file (File -> Save to File)\n" ..
                        "   - Export all scripts (Right-click -> Save to File)\n" ..
                        "   - Put everything in your repo directory\n" ..
                        "   - Make a README.md in any editor u like!\n" ..
                        "4. Commit and push changes to GitHub\n" ..
                        "5. Go to highseas.hackclub.com\n" ..
                        "6. Submit your GitHub repo URL\n\n" ..
                        "Good luck, sailor! 🏴‍☠️"
        )
    end)

    spawn(function()
        while true do
            wait(5)
            updateStatus()
        end
    end)

    -- Add periodic refresh for project name
    spawn(function()
        while true do
            wait(60) -- Refresh every minute
            refreshProjectName()
        end
    end)

	return pluginGui
end

local guiInstance = createGUI() -- Create the GUI

settingsButton.Click:Connect(function()
    guiInstance.Enabled = not guiInstance.Enabled -- Toggle GUI visibility
end)

--- Initialize Plugin ---
loadQueue()
loadAPIKey()
print("Waka Init! Happy Hacking 🏴‍☠️")

-- Load play testing preference
spawn(function()
    TRACK_PLAY_TESTING = plugin:GetSetting("TrackPlayTesting")
    if TRACK_PLAY_TESTING == nil then
        TRACK_PLAY_TESTING = true
        plugin:SetSetting("TrackPlayTesting", true)
    end
end)

spawn(function()
    while true do
        wait(300)
        persistQueue()
    end
end)