AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")

resource.AddFile("materials/wardrobe_ui/body.png")
resource.AddFile("materials/wardrobe_ui/fon.png")

util.AddNetworkString("SandboxWardrobeOpen")
util.AddNetworkString("SandboxWardrobeApply")
util.AddNetworkString("SandboxWardrobeAdminOpen")
util.AddNetworkString("SandboxWardrobeAdminUpdate")
util.AddNetworkString("SandboxWardrobeCommanderOpen")
util.AddNetworkString("SandboxWardrobeCommanderApply")
util.AddNetworkString("SandboxWardrobeSavePreset")

if not file.Exists("wardrobe_presets", "DATA") then
    file.CreateDir("wardrobe_presets")
end

net.Receive("SandboxWardrobeSavePreset", function(len, ply)
    if not IsValid(ply) then return end
    local presets = net.ReadTable()
    local steamID64 = ply:SteamID64()
    if steamID64 then
        local json = util.TableToJSON(presets, true)
        if json then
            file.Write("wardrobe_presets/" .. steamID64 .. ".txt", json)
        end
    end
end)

-- =====================================================================
-- ПСЕВДО-ФУНКЦИИ: Замените на свои реальные проверки!
-- =====================================================================

-- Проверяет, является ли игрок командиром подразделения.
-- Замените тело функции на свою логику, например:
--   return ply:GetNWBool("IsSquadLeader", false)
--   return ply:Team() == TEAM_COMMANDER
--   return ply.isCommander == true
local function IsCommander(ply)
    -- ЗАГЛУШКА: Сейчас возвращает true для суперадминов.
    -- Замените на реальную проверку!
    return IsValid(ply) and ply:IsSuperAdmin()
end

-- Возвращает таблицу игроков, которые находятся в подразделении этого командира.
-- Замените тело функции на свою логику, например:
--   return GetSquadByLeader(ply)
--   return team.GetPlayers(ply:Team())
--   return ply:GetSquadMembers()
local function GetSquadMembers(commander)
    -- ЗАГЛУШКА: Сейчас возвращает всех игроков на сервере кроме самого командира.
    -- Замените на реальную логику получения списка подразделения!
    local members = {}
    for _, ply in ipairs(player.GetAll()) do
        if ply ~= commander then
            table.insert(members, ply)
        end
    end
    return members
end

-- =====================================================================
-- СИСТЕМА РАЗБЛОКИРОВКИ БОДИГРУПП (АДМИН)
-- =====================================================================

local function SanitizeData(tbl, depth)
    depth = depth or 1
    local out = {}
    for k, v in pairs(tbl) do
        local keyStr = tostring(k)
        if depth == 1 then
            if type(k) == "number" and k > 1e15 then continue end
            if type(k) == "string" and string.find(keyStr, "e%+") then continue end
        end
        if type(v) == "table" then
            out[keyStr] = SanitizeData(v, depth + 1)
        else
            out[keyStr] = v
        end
    end
    return out
end

function LoadWardrobeUnlocked()
    if file.Exists("wardrobe_unlocked.txt", "DATA") then
        local content = file.Read("wardrobe_unlocked.txt", "DATA")
        local parsed = util.JSONToTable(content, true, true)
        if parsed then
            WARDROBE_UNLOCKED = SanitizeData(parsed)
        else
            WARDROBE_UNLOCKED = {}
        end
    else
        WARDROBE_UNLOCKED = {}
    end
end
LoadWardrobeUnlocked()

function SaveWardrobeUnlocked()
    local json = util.TableToJSON(WARDROBE_UNLOCKED, true)
    if json then
        file.Write("wardrobe_unlocked.txt", json)
    end
end

-- =====================================================================
-- АДМИН ПАНЕЛЬ
-- =====================================================================

concommand.Add("wardrobe_admin", function(ply, cmd, args)
    if IsValid(ply) and not ply:IsSuperAdmin() then
        ply:ChatPrint("У вас нет прав (нужна группа superadmin).")
        return
    end
    net.Start("SandboxWardrobeAdminOpen")
    net.WriteTable(WARDROBE_UNLOCKED)
    net.Send(ply)
end)

net.Receive("SandboxWardrobeAdminUpdate", function(len, ply)
    if not IsValid(ply) or not ply:IsSuperAdmin() then return end
    
    local sid64 = net.ReadString()
    local model = string.lower(net.ReadString())
    local bg_id = tostring(net.ReadUInt(8))
    local bg_val = tostring(net.ReadUInt(8))
    local state = net.ReadBool()
    
    WARDROBE_UNLOCKED[sid64] = WARDROBE_UNLOCKED[sid64] or {}
    WARDROBE_UNLOCKED[sid64][model] = WARDROBE_UNLOCKED[sid64][model] or {}
    WARDROBE_UNLOCKED[sid64][model][bg_id] = WARDROBE_UNLOCKED[sid64][model][bg_id] or {}
    
    if state then
        WARDROBE_UNLOCKED[sid64][model][bg_id][bg_val] = true
    else
        WARDROBE_UNLOCKED[sid64][model][bg_id][bg_val] = nil
        if table.IsEmpty(WARDROBE_UNLOCKED[sid64][model][bg_id]) then WARDROBE_UNLOCKED[sid64][model][bg_id] = nil end
        if table.IsEmpty(WARDROBE_UNLOCKED[sid64][model]) then WARDROBE_UNLOCKED[sid64][model] = nil end
        if table.IsEmpty(WARDROBE_UNLOCKED[sid64]) then WARDROBE_UNLOCKED[sid64] = nil end
    end
    
    SaveWardrobeUnlocked()
end)

-- =====================================================================
-- ПАНЕЛЬ КОМАНДИРА
-- =====================================================================

concommand.Add("wardrobe_commander", function(ply, cmd, args)
    if not IsValid(ply) then return end
    if not IsCommander(ply) then
        ply:ChatPrint("Вы не являетесь командиром подразделения.")
        return
    end
    
    local members = GetSquadMembers(ply)
    local membersData = {}
    for _, member in ipairs(members) do
        if IsValid(member) then
            table.insert(membersData, {
                nick = member:Nick(),
                sid64 = member:SteamID64(),
                model = member:GetModel(),
                entIndex = member:EntIndex(),
            })
        end
    end
    
    net.Start("SandboxWardrobeCommanderOpen")
    net.WriteTable(membersData)
    net.Send(ply)
end)

net.Receive("SandboxWardrobeCommanderApply", function(len, ply)
    if not IsValid(ply) then return end
    if not IsCommander(ply) then return end
    
    local targetEntIndex = net.ReadUInt(16)
    local isWipe = net.ReadBool()
    
    local target = Entity(targetEntIndex)
    if not IsValid(target) or not target:IsPlayer() then
        ply:ChatPrint("Целевой игрок не найден.")
        return
    end
    
    -- Проверяем что целевой игрок находится в подразделении командира
    local members = GetSquadMembers(ply)
    local isMember = false
    for _, member in ipairs(members) do
        if member == target then
            isMember = true
            break
        end
    end
    
    if not isMember then
        ply:ChatPrint("Этот игрок не в вашем подразделении.")
        return
    end
    
    if isWipe then
        target:SetSkin(0)
        local bgs = target:GetBodyGroups()
        for _, bg in ipairs(bgs) do
            target:SetBodygroup(bg.id, 0)
        end
        ply:ChatPrint("Сброшена экипировка для: " .. target:Nick())
        return
    end

    local bodygroups = net.ReadTable()
    local skin = net.ReadUInt(8)

    for idx, value in pairs(bodygroups) do
        target:SetBodygroup(idx, value)
    end
    target:SetSkin(skin)
    
    ply:ChatPrint("Экипировка применена для: " .. target:Nick())
end)

-- =====================================================================
-- ЛОГИКА ЭНТИТИ ГАРДЕРОБА
-- =====================================================================

function ENT:Initialize()
    self:SetModel("models/props_wasteland/controlroom_storagecloset001a.mdl")
    self:PhysicsInit(SOLID_VPHYSICS)
    self:SetMoveType(MOVETYPE_VPHYSICS)
    self:SetSolid(SOLID_VPHYSICS)
    self:SetUseType(SIMPLE_USE) 
    
    local phys = self:GetPhysicsObject()
    if IsValid(phys) then phys:Wake() end
    
    self.playerCooldowns = {}
end

function ENT:GetModelBodygroups(model)
    local tempEnt = ents.Create("prop_dynamic")
    if not IsValid(tempEnt) then return {} end
    tempEnt:SetModel(model)
    tempEnt:Spawn()
    
    local bodygroups = {}
    for i = 0, tempEnt:GetNumBodyGroups() - 1 do
        local name = tempEnt:GetBodygroupName(i)
        local count = tempEnt:GetBodygroupCount(i)
        if count > 1 then
            bodygroups[i] = {name = name, count = count, index = i}
        end
    end
    
    tempEnt:Remove()
    return bodygroups
end

function ENT:GetModelSkinCount(model)
    local tempEnt = ents.Create("prop_dynamic")
    if not IsValid(tempEnt) then return 0 end
    tempEnt:SetModel(model)
    tempEnt:Spawn()
    
    local skinCount = tempEnt:SkinCount() or 0
    tempEnt:Remove()
    return skinCount
end

function ENT:Use(activator)
    if not IsValid(activator) or not activator:IsPlayer() then return end
    
    local steamID = activator:SteamID()
    local now = CurTime()
    if self.playerCooldowns[steamID] and (now - self.playerCooldowns[steamID]) < 2 then return end
    
    local model = activator:GetModel()
    if not model then return end

    local bodygroups = self:GetModelBodygroups(model)
    local skinCount = self:GetModelSkinCount(model)
    
    local availableBodygroups = {}
    for idx, data in pairs(bodygroups) do
        availableBodygroups[idx] = data
    end
    
    local availableSkins = {}
    for i = 0, skinCount - 1 do
        table.insert(availableSkins, i)
    end

    local currentBodygroups = {}
    for idx in pairs(availableBodygroups) do
        currentBodygroups[idx] = activator:GetBodygroup(idx)
    end
    
    local currentSkin = activator:GetSkin()
    
    local steamID64 = activator:SteamID64()
    local unlocked = {}
    if steamID64 and WARDROBE_UNLOCKED[steamID64] and WARDROBE_UNLOCKED[steamID64][string.lower(model)] then
        unlocked = WARDROBE_UNLOCKED[steamID64][string.lower(model)]
    end
    
    local presets = {}
    if steamID64 and file.Exists("wardrobe_presets/" .. steamID64 .. ".txt", "DATA") then
        local content = file.Read("wardrobe_presets/" .. steamID64 .. ".txt", "DATA")
        if content and content ~= "" then
            presets = util.JSONToTable(content) or {}
        end
    end

    self.playerCooldowns[steamID] = now
    
    net.Start("SandboxWardrobeOpen")
    net.WriteString(model)
    net.WriteTable(availableBodygroups)
    net.WriteTable(availableSkins)
    net.WriteTable(currentBodygroups)
    net.WriteUInt(currentSkin, 8)
    net.WriteTable(unlocked)
    net.WriteTable(presets)
    net.Send(activator)
end

net.Receive("SandboxWardrobeApply", function(len, client)
    if not IsValid(client) then return end
    
    local isWipe = net.ReadBool()

    if isWipe then
        client:SetSkin(0)
        local bgs = client:GetBodyGroups()
        for _, bg in ipairs(bgs) do
            client:SetBodygroup(bg.id, 0)
        end
        return
    end

    local bodygroups = net.ReadTable()
    local skin = net.ReadUInt(8)

    for idx, value in pairs(bodygroups) do
        client:SetBodygroup(idx, value)
    end

    client:SetSkin(skin)
end)
