ix.util.Include("cl_plugin.lua")
ix.util.Include("sv_plugin.lua")

local PLUGIN = PLUGIN
PLUGIN.name = "Admin Mode"
PLUGIN.author = "Scripty"
PLUGIN.description = "Перекид игрока по команде в админ фракцию"

local accessAdminGroups = {
    ["superadmin"] = true,
    ["super admin"] = true,
    ["projectteam"] = true,
    ["teh.admin"] = true,
    ["curator"] = true,
    ["sudo-curator"] = true,
    ["asist-sudo"] = true,
    ["admin"] = true,
    ["st.admin"] = true,
    ["ivent"] = true,
    ["st.event"] = true,
    ["event"] = true,
    ["disp"] = true,
    ["assistant"] = true,
    ["specadmin"] = true
}
local playerMeta = FindMetaTable("Player")

function playerMeta:IsAdminMode()
    return self:GetNetVar("AdminMode", false)
end

local function CanUseAdminMode(ply)
    return accessAdminGroups[ply:GetUserGroup()] == true
end

local function CanUseNoclip(ply)
    if ply:IsAdminMode() then return true end
    
    if ply:GetUserGroup() == "superadmin" then return true end
    
    return false
end

local function GetWeaponsList(ply)
    local list = {}
    for _, wep in ipairs(ply:GetWeapons()) do
        if IsValid(wep) then
            list[#list + 1] = wep:GetClass()
        end
    end
    return list
end

if (SERVER) then
    util.AddNetworkString("AdminMode_Groups")

    hook.Add("PlayerInitialSpawn", "AdminMode_SendGroups", function(ply)
        net.Start("AdminMode_Groups")
        net.WriteTable(accessAdminGroups)
        net.Send(ply)
    end)

    function PLUGIN:PlayerDisconnected(ply)
        if ply:IsAdminMode() then
            local char = ply:GetCharacter()
            if char then
                local oldFaction = char:GetData("AdminMode_OldFaction")
                if oldFaction then char:SetFaction(oldFaction) end

                local oldPodr = char:GetData("AdminMode_OldPodr")
                if oldPodr then char:SetPodr(oldPodr) end

                local oldSpec = char:GetData("AdminMode_OldSpec")
                if oldSpec then char:SetSpec(oldSpec) end

                local oldRank = char:GetData("AdminMode_OldRank")
                if oldRank then char:SetRank(oldRank) end
            end
            ply:SetNetVar("HideFromTab", false)
            ply:SetNetVar("AdminMode", false)
        end
    end

    function PLUGIN:PlayerLoadedCharacter(ply, char)
        local squads = ix.plugin.list["squads"]

        if ply:IsAdminMode() and squads then
            local squad, squadID = squads:GetPlayerSquad(ply)
            if squad then
                if squad.leader == ply:SteamID() then
                    squads:DisbandSquad(squadID)
                else
                    squads:LeaveSquad(ply)
                end
                net.Start("ixSquadSync")
                    net.WriteString("{}")
                net.Send(ply)
            end
        end

        if char:GetFaction() == FACTION_ADMIN and not ply:IsAdminMode() then

            local oldFaction = char:GetData("AdminMode_OldFaction")
            local oldPodr = char:GetData("AdminMode_OldPodr")
            local oldSpec = char:GetData("AdminMode_OldSpec")
            local oldRank = char:GetData("AdminMode_OldRank")

            if oldFaction then char:SetFaction(oldFaction) end
            if oldPodr then char:SetPodr(oldPodr) end
            if oldSpec then char:SetSpec(oldSpec) end
            if oldRank then char:SetRank(oldRank) end

            char:SetData("AdminMode_OldFaction", nil)
            char:SetData("AdminMode_OldPodr", nil)
            char:SetData("AdminMode_OldSpec", nil)
            char:SetData("AdminMode_OldRank", nil)
            char:SetData("AdminMode_OldModel", nil)
            char:SetData("AdminMode_OldWeapons", nil)

            ply:SetNetVar("AdminMode", false)
            ply:SetNetVar("HideFromTab", false)

            local radio = ix.plugin.list["radio"]
            if radio then
                radio:SyncRadioState(ply, radio.defaultFrequency, false, false)
            end
        elseif ply:IsAdminMode() and char:GetFaction() ~= FACTION_ADMIN then
            self:ToggleAdminMode(ply)
        end

        if ply:IsAdminMode() then
            local radio = ix.plugin.list["radio"]
            if radio then
                radio:SyncRadioState(ply, radio.defaultFrequency, false, false)
            end
        end
    end

    function PLUGIN:OnCharacterSave(char)
        local ply = char:GetPlayer()
        if not IsValid(ply) then return end

        if ply:IsAdminMode() then
            local oldFaction = char:GetData("AdminMode_OldFaction")
            if oldFaction then char:SetFaction(oldFaction) end

            local oldPodr = char:GetData("AdminMode_OldPodr")
            if oldPodr then char:SetPodr(oldPodr) end

            local oldSpec = char:GetData("AdminMode_OldSpec")
            if oldSpec then char:SetSpec(oldSpec) end

            local oldRank = char:GetData("AdminMode_OldRank")
            if oldRank then char:SetRank(oldRank) end

            ply:SetNetVar("AdminMode", false)
        end
    end

    function PLUGIN:ToggleAdminMode(ply)
        if not IsValid(ply) then return end
        if not CanUseAdminMode(ply) then
            ply:ChatPrint("[!] У вас нет доступа к админ-моду.")
            return
        end

        local char = ply:GetCharacter()
        if not char then
            ply:ChatPrint("[!] У вас нет активного персонажа.")
            return
        end

        local enable = not ply:IsAdminMode()
        ply:SetNetVar("AdminMode", enable)

        if enable then
            local squads = ix.plugin.list["squads"]
            if squads then
                local squad, squadID = squads:GetPlayerSquad(ply)
                if squad then
                    if squad.leader == ply:SteamID() then
                        squads:DisbandSquad(squadID)
                    else
                        squads:LeaveSquad(ply)
                    end
                end
            end
            char:SetData("AdminMode_OldFaction", char:GetFaction())
            char:SetData("AdminMode_OldPodr", char:GetPodr())
            char:SetData("AdminMode_OldSpec", char:GetSpec())
            char:SetData("AdminMode_OldRank", char:GetRank())

            char:SetData("AdminMode_OldModel", ply:GetModel())
            char:SetData("AdminMode_OldWeapons", GetWeaponsList(ply))

            ply:SetModel("models/ft/ft_admin.mdl")

            if FACTION_ADMIN then
                char:SetFaction(FACTION_ADMIN)
            end

            ply:GodEnable()
            ply:SetNoDraw(true)
            ply:SetMoveType(MOVETYPE_NOCLIP)

            ply:StripWeapons()
            ply:Give("weapon_physgun")
            ply:Give("gmod_tool")
            ply:Give("ix_hands")
            ply:SelectWeapon("ix_hands")
            ply:SetNetVar("HideFromTab", true)

            ply:ChatPrint("[!] Админ-мод включен.")
        else
            local oldFaction = char:GetData("AdminMode_OldFaction")
            local oldPodr = char:GetData("AdminMode_OldPodr")
            local oldSpec = char:GetData("AdminMode_OldSpec")
            local oldRank = char:GetData("AdminMode_OldRank")

            if oldFaction and char:GetFaction() == FACTION_ADMIN then char:SetFaction(oldFaction) end
            if oldPodr then char:SetPodr(oldPodr) end
            if oldSpec then char:SetSpec(oldSpec) end
            if oldRank then char:SetRank(oldRank) end

            local oldModel = char:GetData("AdminMode_OldModel")
            if oldModel then
                ply:SetModel(oldModel)
            end

            local oldWeapons = char:GetData("AdminMode_OldWeapons") or {}
            ply:StripWeapons()

            for _, class in ipairs(oldWeapons) do
                ply:Give(class)
            end

            if ply.sam_uncloak then
                ply:sam_uncloak()
            end

            ply:SetNoDraw(false)
            ply:SetRenderMode(RENDERMODE_NORMAL)
            ply:SetColor(Color(255, 255, 255, 255))
            ply:Fire("alpha", 255, 0)
            ply:DrawWorldModel(true)
            ply:SetMaterial("")
            
            ply:SetNetVar("ixNoDraw", false)
            ply:DrawShadow(true)
            ply:SetupHands()

            if #oldWeapons == 0 then
                ply:Give("ix_hands")
            end

            ply:GodDisable()
            ply:SetMoveType(MOVETYPE_WALK)

            local restoredFaction = char:GetFaction()
            local class = char:GetClass() or "default"

            local spawnPlugin = ix.plugin.list["spawns"]

            if spawnPlugin and spawnPlugin.spawns then
                local factionTable = ix.faction.indices[restoredFaction]

                if factionTable then
                    local factionID = factionTable.uniqueID
                    local factionSpawns = spawnPlugin.spawns[factionID]

                    if factionSpawns then
                        local className = "default"

                        for _, v in ipairs(ix.class.list) do
                            if v.index == class then
                                className = v.uniqueID
                                break
                            end
                        end

                        local points = factionSpawns[className] or factionSpawns["default"]

                        if points and not table.IsEmpty(points) then
                            local pos = table.Random(points)

                            timer.Simple(0.1, function()
                                if IsValid(ply) then
                                    ply:SetPos(pos)
                                end
                            end)
                        end
                    end
                end
            end

            char:SetData("AdminMode_OldFaction", nil)
            char:SetData("AdminMode_OldPodr", nil)
            char:SetData("AdminMode_OldSpec", nil)
            char:SetData("AdminMode_OldRank", nil)
            char:SetData("AdminMode_OldModel", nil)
            char:SetData("AdminMode_OldWeapons", nil)
            ply:SetNetVar("HideFromTab", false)
            local radio = ix.plugin.list["radio"]
            if radio then
                radio:SyncRadioState(ply, radio.defaultFrequency, false, false)
            end
            ply:ChatPrint("[!] Админ-мод выключен.")
        end

        hook.Run("PlayerAdminModeToggled", ply, enable)
    end

    function PLUGIN:EntityTakeDamage(target, dmg)
        if IsValid(target) and target:IsPlayer() and target:IsAdminMode() then
            return true
        end

        local attacker = dmg:GetAttacker()
        if IsValid(attacker) and attacker:IsPlayer() and attacker:IsAdminMode() then
            return true
        end
    end

    function PLUGIN:OnCharacterVarChanged(char, key, oldValue, newValue)
        if (key == "faction") then
            local ply = char:GetPlayer()

            if (IsValid(ply) and ply:IsAdminMode() and newValue ~= FACTION_ADMIN) then
                self:ToggleAdminMode(ply)
            end
        end
    end

    function PLUGIN:PlayerNoClip(ply, desiredState)
        if not IsValid(ply) then return false end

        if CanUseNoclip(ply) then
            ply:SetNoDraw(desiredState)

            if desiredState then
                ply:SetRenderMode(RENDERMODE_NONE)
                ply:SetColor(Color(255, 255, 255, 0))
            else
                ply:SetRenderMode(RENDERMODE_NORMAL)
                ply:SetColor(Color(255, 255, 255, 255))
            end

            if desiredState then
                ply:SetNetVar("HideFromTab", true)
                ply:SetNetVar("ixNoDraw", true)
            else
                if not ply:IsAdminMode() then
                    ply:SetNetVar("HideFromTab", false)
                    ply:SetNetVar("ixNoDraw", false)
                end
            end

            return true
        end

        return false
    end

    ix.command.Add("admin", {
        description = "Включить/выключить админ-мод.",
        OnRun = function(self, ply)
            PLUGIN:ToggleAdminMode(ply)
        end
    })

    ix.command.Add("adm", {
        description = "Синоним /admin.",
        OnRun = function(self, ply)
            PLUGIN:ToggleAdminMode(ply)
        end
    })

end

CLIENT_ADMIN_GROUPS = CLIENT_ADMIN_GROUPS or {}

if CLIENT then
    net.Receive("AdminMode_Groups", function()
        CLIENT_ADMIN_GROUPS = net.ReadTable()
    end)
end
