local meta = FindMetaTable("Player")

function meta:MoveItem(from_con_id, from_slot, to_con_id, to_slot)
	net.Start("ItemStore_Move")
		net.WriteUInt(from_con_id, 32)
		net.WriteUInt(from_slot, 32)
		net.WriteUInt(to_con_id, 32)
		net.WriteUInt(to_slot, 32)
	net.SendToServer()
end

function meta:UseItem(con_id, slot, ...)
	net.Start("ItemStore_Use")
		net.WriteUInt(con_id, 32)
		net.WriteUInt(slot, 32)
		net.WriteTable({...})
	net.SendToServer()
end

function meta:UseItemWith(from_con_id, from_slot, to_con_id, to_slot)
	net.Start("ItemStore_UseWith")
		net.WriteUInt(from_con_id, 32)
		net.WriteUInt(from_slot, 32)
		net.WriteUInt(to_con_id, 32)
		net.WriteUInt(to_slot, 32)
	net.SendToServer()
end

function meta:DropItem(con_id, slot)
	net.Start("ItemStore_Drop")
		net.WriteUInt(con_id, 32)
		net.WriteUInt(slot, 32)
	net.SendToServer()
end

function meta:DestroyItem(con_id, slot)
	net.Start("ItemStore_Destroy")
		net.WriteUInt(con_id, 32)
		net.WriteUInt(slot, 32)
	net.SendToServer()
end

function meta:MergeItem(from_con_id, from_slot, to_con_id, to_slot)
	net.Start("ItemStore_Merge")
		net.WriteUInt(from_con_id, 32)
		net.WriteUInt(from_slot, 32)
		net.WriteUInt(to_con_id, 32)
		net.WriteUInt(to_slot, 32)
	net.SendToServer()
end

function meta:SplitItem(con_id, slot, amount)
	net.Start("ItemStore_Split")
		net.WriteUInt(con_id, 32)
		net.WriteUInt(slot, 32)
		net.WriteUInt(amount, 16)
	net.SendToServer()
end

local acttime = 0
local actdelay = 0
local acttext = ""
local offset_x
local offset_y
local function DrawProgressBar(label, color, filled, remain)
	filled = math.Clamp(filled, 0, 1)
	surface.SetFont("DermaDefaultBold")
	local sizex = surface.GetTextSize(acttext)
	local w, h = sizex >= 85 and sizex + 15 or 100, 15
	local centerx, centery = offset_x or ScrW() / 2, offset_y or ScrH() / 2 - 50
	local x, y = centerx - w / 2, centery - h / 2
	surface.SetDrawColor(Color(255, 255, 255, 200))
	surface.DrawOutlinedRect(x, y, w, h)
	surface.SetDrawColor(color)
	surface.DrawRect(x + 2, y + 2, (w - 4) * filled, h - 4)
	surface.SetDrawColor(color)
	surface.DrawRect(x + 2, y + 2, (w - 4) * filled, h - 4)
	draw.SimpleTextOutlined(label, "DermaDefaultBold", centerx, centery - 1, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, color_black)
	draw.SimpleTextOutlined(remain, "DermaDefaultBold", centerx, centery + 13, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, color_black)
	draw.SimpleTextOutlined(itemstore.Translate("runtocancel"), "DermaDefaultBold", centerx, centery + 24, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, color_black)
end

local function ProgressDraw()
	local ply = LocalPlayer()
	if !ply:Alive() or ply:isArrested() then return end
	local curtime = CurTime()
	DrawProgressBar(acttext, Color(200, 200, 0, 200), (curtime - acttime) / actdelay, math.max(0, math.Round(acttime - curtime + actdelay, 1)))
end

local function StopCommands(ply, cmd)
	if !ply:Alive() or ply:isArrested() then return end
	if cmd:KeyDown(IN_ATTACK) or cmd:KeyDown(IN_ATTACK2) or cmd:KeyDown(IN_RELOAD) then
		cmd:RemoveKey(IN_ATTACK)
		cmd:RemoveKey(IN_ATTACK2)
		cmd:RemoveKey(IN_RELOAD)
	end
end

usermessage.Hook("ItemStore_DelayAction", function(msg)
	local ply = LocalPlayer()
	if !IsValid(ply) then return end
	ply.ItemStore_SpeedModifier = msg:ReadFloat()
	acttime = CurTime()
	actdelay = msg:ReadFloat()
	acttext = msg:ReadString()
	if actdelay != 0 then
		hook.Add("HUDPaint", "ItemStore_DelayAction", ProgressDraw, HOOK_LOW or 1)
		hook.Add("StartCommand", "ItemStore_DelayAction", StopCommands)
	else
		hook.Remove("HUDPaint", "ItemStore_DelayAction")
		hook.Remove("StartCommand", "ItemStore_DelayAction")
	end
end)

hook.Add("InitPostEntity", "ItemStore_RequestInventory", function()
	hook.Remove("InitPostEntity", "ItemStore_RequestInventory")
	net.Start("ItemStore_SyncInventory")
	net.SendToServer()
end)

local inv
local refresh_inv
local function CreateItemStoreContainer()
	if !itemstore.config.ContextInventory then return end
	if refresh_inv then
		if IsValid(inv) then
			inv:Remove()
			inv = nil
		end
		inv = vgui.Create("ItemStoreContainerWindow", g_ContextMenu)
		inv:SetTitle(itemstore.Translate("inventory"))
		inv:SetContainerID(LocalPlayer().InventoryID)
		inv:RemoveCloseButton()
		inv:SetDraggable(false)
		inv:InvalidateLayout(true)
		inv:SetPos(ScrW() / 2 - inv:GetWide() / 2, ScrH() - inv:GetTall())
	end
end

net.Receive("ItemStore_SyncInventory", function()
	local ply = LocalPlayer()
	if !IsValid(ply) then return end
	ply.InventoryID = net.ReadUInt(32)
	refresh_inv = true
	if IsValid(g_ContextMenu) and g_ContextMenu:IsVisible() then
		CreateItemStoreContainer()
	end
end)

hook.Add("ContextMenuOpened", "ItemStore_CreateInventory", function()
	CreateItemStoreContainer()
end)

net.Receive("ItemStore_BuyUpgrade", function()
	LocalPlayer().ItemStore_Upgrades = net.ReadTable()
end)

local containers = {}
net.Receive("ItemStore_Open", function()
	local ply = LocalPlayer()
	if !IsValid(ply) then return end
	local id = net.ReadUInt(32)
	local name = net.ReadString()
	local hideinv = net.ReadBit() == 1
	local con = itemstore.containers.Get(id)
	local admin = net.ReadBool()
	if !con then return end
	if IsValid(containers[id]) then
		containers[id]:Remove()
	end
	containers[id] = vgui.Create("ItemStoreContainerWindow")
	local container = containers[id]
	container:SetContainerID(id)
	container:SetTitle(name)
	container:Center()
	container:MakePopup()
	local think = container.Think
	function container:Think()
		think(self)
		local x, y = container:GetPos()
		offset_x = x + (container:GetWide() / 2)
		offset_y = y - 40
	end
	function container:OnRemove()
		offset_x = nil
		offset_y = nil
	end
	if !admin then
		container:ParentToHUD()
	end
	if !hideinv then
		local inv = vgui.Create("ItemStoreContainerWindow")
		inv:SetContainerID(ply.InventoryID)
		inv:SetTitle(itemstore.Translate("inventory"))
		inv:RemoveCloseButton()
		inv:MakePopup()
		if !admin then
			inv:ParentToHUD()
		end
		inv:InvalidateLayout(true)
		local think = inv.Think
		function inv:Think()
			think(self)
			if !IsValid(container) then inv:Close() return end
			local x, y = container:GetPos()
			inv:SetPos(x + (container:GetWide() / 2 - inv:GetWide() / 2), y + container:GetTall() + 10)
		end
		function container:OnClose()
			inv:Close()
		end
		local x, y = container:GetPos()
		container:SetPos(x, y - inv:GetTall() / 2)
		if name == itemstore.Translate("bank") and !admin then
			if !table.IsEmpty(itemstore.config.Upgrades) then
				local upgrades_cnt = table.Count(itemstore.config.Upgrades)
				local upgrades = vgui.Create("DFrame")
				upgrades:SetWide(container:GetWide())
				upgrades:SetTall(upgrades_cnt * 30 + 20)
				upgrades:SetTitle(itemstore.Translate("upgrades"))
				upgrades:ShowCloseButton(false)
				upgrades:MakePopup()
				upgrades:ParentToHUD()
				function upgrades:Paint(w, h)
					surface.SetDrawColor(Color(100, 100, 100, 200))
					surface.DrawRect(0, 22, w, h - 22)
					surface.SetDrawColor(Color(44, 62, 80))
					surface.DrawRect(0, 0, w, 22)
				end
				local think = upgrades.Think
				function upgrades:Think()
					think(self)
					if !IsValid(container) then upgrades:Close() return end
					local x, y = container:GetPos()
					upgrades:SetPos(x + (container:GetWide() / 2 - upgrades:GetWide() / 2), y + container:GetTall() + inv:GetTall() + 20)
				end
				function container:OnClose()
					upgrades:Close()
				end
				local u_list = vgui.Create("DScrollPanel", upgrades)
				u_list:Dock(FILL)
				for k, v in SortedPairsByMemberValue(itemstore.config.Upgrades, "price") do
					local u_pan = vgui.Create("DButton", u_list)
					u_pan:SetText(v.name.." ($"..string.Comma(v.price)..")")
					u_pan:SetTall(20)
					u_pan:Dock(TOP)
					u_pan:DockMargin(0, 0, 0, 5)
					u_pan.DoClick = function()
						local menu = DermaMenu()
						menu:AddOption(itemstore.Translate("purchase"), function()
							net.Start("ItemStore_BuyUpgrade")
								net.WriteUInt(k, 16)
							net.SendToServer()
							container:Remove()
						end):SetIcon("icon16/money_dollar.png")
						menu:Open()
					end
					u_pan.Think = function()
						if ply.ItemStore_Upgrades and ply.ItemStore_Upgrades[k] then
							u_pan:SetText(v.name.." (Gekauft)")
							u_pan:SetDisabled(true)
						else
							u_pan:SetText(v.name.." ($"..string.Comma(v.price)..")")
							u_pan:SetDisabled(false)
						end
					end
				end
				local x, y = container:GetPos()
				container:SetPos(x, y - upgrades:GetTall() / 2)
			end

			local sorting = vgui.Create("DFrame")
			sorting:SetWide(container:GetWide())
			sorting:SetTall(60)
			sorting:SetTitle(itemstore.Translate("actions"))
			sorting:ShowCloseButton(false)
			sorting:MakePopup()
			sorting:ParentToHUD()
			function sorting:Paint(w, h)
				surface.SetDrawColor(Color(100, 100, 100, 200))
				surface.DrawRect(0, 22, w, h - 22)
				surface.SetDrawColor(Color(44, 62, 80))
				surface.DrawRect(0, 0, w, 22)
			end
			local think = sorting.Think
			function sorting:Think()
				think(self)
				if !IsValid(container) then sorting:Close() return end
				local x, y = container:GetPos()
				sorting:SetPos(x + (container:GetWide() / 2 - sorting:GetWide() / 2), y - 70)
			end
			function container:OnClose()
				sorting:Close()
			end
			local u_list = vgui.Create("DScrollPanel", sorting)
			u_list:Dock(FILL)

			local u_pan = vgui.Create("DButton", u_list)
			u_pan:SetText(itemstore.Translate("combineallitems"))
			u_pan:SetTall(20)
			u_pan:Dock(TOP)
			u_pan:DockMargin(0, 0, 0, 5)
			u_pan.DoClick = function()
				net.Start("ItemStore_MassMerge")
				net.SendToServer()
			end
		end
	end
end)