-- lua/autorun/mrp_handcuffs_ext.lua
-- Realistic Handcuffs Extension for Military RP

if SERVER then
    util.AddNetworkString("MRP_Handcuffs_PerformJail")
    util.AddNetworkString("RHC_Jailer_Menu")
    util.AddNetworkString("MRP_Handcuffs_PerformUnjail")
    util.AddNetworkString("MRP_Handcuffs_OpenInteract")
    util.AddNetworkString("MRP_Handcuffs_DoInteract")
    util.AddNetworkString("MRP_UpdateJailInfo")

    -- Data persistence for cells
    local cellFilePath = "mrp_jailcells.txt"
    MRP_JailCells = {RF = {}, UK = {}}
    if file.Exists(cellFilePath, "DATA") then
        local data = util.JSONToTable(file.Read(cellFilePath, "DATA") or "{}") or {}
        MRP_JailCells.RF = data.RF or {}
        MRP_JailCells.UK = data.UK or {}
    end

    local function SaveCells()
        file.Write(cellFilePath, util.TableToJSON(MRP_JailCells))
    end

    -- Helper to get player being looked at
    local function GetTarget(ply)
        local tr = ply:GetEyeTrace()
        if IsValid(tr.Entity) and tr.Entity:IsPlayer() and tr.Entity:GetPos():DistToSqr(ply:GetPos()) < 100000 then
            return tr.Entity
        end
        return nil
    end

    -- Console commands as fallback for setting cells
    concommand.Add("mrp_setcellrf", function(ply, cmd, args)
        if IsValid(ply) and not ply:IsSuperAdmin() then return end
        local cellNum = tonumber(args[1])
        if cellNum and cellNum >= 1 and cellNum <= 3 then
            MRP_JailCells.RF[cellNum] = ply:GetPos()
            SaveCells()
            if IsValid(ply) then ply:ChatPrint("Позиция камеры РФ " .. cellNum .. " установлена на ваше местоположение.") else print("Set.") end
        else
            if IsValid(ply) then ply:ChatPrint("Использование: mrp_setcellrf [1-3] в консоли") end
        end
    end)

    concommand.Add("mrp_setcelluk", function(ply, cmd, args)
        if IsValid(ply) and not ply:IsSuperAdmin() then return end
        local cellNum = tonumber(args[1])
        if cellNum and cellNum >= 1 and cellNum <= 3 then
            MRP_JailCells.UK[cellNum] = ply:GetPos()
            SaveCells()
            if IsValid(ply) then ply:ChatPrint("Позиция камеры УК " .. cellNum .. " установлена на ваше местоположение.") else print("Set.") end
        else
            if IsValid(ply) then ply:ChatPrint("Использование: mrp_setcelluk [1-3] в консоли") end
        end
    end)
    


    -- Chat commands
    hook.Add("PlayerSay", "MRP_Handcuffs_ChatCommands", function(ply, text)
        local args = string.Explode(" ", string.lower(text))
        local cmd = args[1]

        if cmd == "/setcellrf" then
            if not ply:IsSuperAdmin() then return "" end
            local cellNum = tonumber(args[2])
            if cellNum and cellNum >= 1 and cellNum <= 3 then
                MRP_JailCells.RF[cellNum] = ply:GetPos()
                SaveCells()
                ply:ChatPrint("Позиция камеры РФ " .. cellNum .. " установлена на ваше местоположение.")
            else
                ply:ChatPrint("Использование: /setcellrf [1-3] (Смотрите на место или стойте там)")
            end
            return "" -- suppress chat
        end
        
        if cmd == "/setcelluk" then
            if not ply:IsSuperAdmin() then return "" end
            local cellNum = tonumber(args[2])
            if cellNum and cellNum >= 1 and cellNum <= 3 then
                MRP_JailCells.UK[cellNum] = ply:GetPos()
                SaveCells()
                ply:ChatPrint("Позиция камеры УК " .. cellNum .. " установлена на ваше местоположение.")
            else
                ply:ChatPrint("Использование: /setcelluk [1-3] (Смотрите на место или стойте там)")
            end
            return "" -- suppress chat
        end

        local function HasPoliceAccess(p)
            return true
        end

        if cmd == "/gag" then
            if not HasPoliceAccess(ply) then return "" end
            local target = GetTarget(ply)
            if target and target:GetNWBool("rhc_cuffed", false) then
                local isGagged = target:GetNWBool("MRP_Gagged", false)
                target:SetNWBool("MRP_Gagged", not isGagged)
                ply:ChatPrint(target:Nick() .. " теперь " .. (not isGagged and "с кляпом" or "без кляпа") .. ".")
            else
                ply:ChatPrint("Вы должны смотреть на закованного игрока.")
            end
            return ""
        elseif cmd == "/blind" then
            if not HasPoliceAccess(ply) then return "" end
            local target = GetTarget(ply)
            if target and target:GetNWBool("rhc_cuffed", false) then
                local isBlind = target:GetNWBool("MRP_Blindfolded", false)
                target:SetNWBool("MRP_Blindfolded", not isBlind)
                if not isBlind then
                    target:PrintMessage(HUD_PRINTCENTER, "Вам завязали глаза.")
                end
                ply:ChatPrint(target:Nick() .. " теперь " .. (not isBlind and "с завязанными глазами" or "без повязки на глазах") .. ".")
            else
                ply:ChatPrint("Вы должны смотреть на закованного игрока.")
            end
            return ""
        end
    end)
    
    -- Mute gagged players in voice
    hook.Add("PlayerCanHearPlayersVoice", "MRP_Handcuffs_GagVoice", function(listener, talker)
        if IsValid(talker) and talker:GetNWBool("MRP_Gagged", false) then
            return false, false
        end
    end)
    
    -- Mute gagged players in text chat (Helix override)
    hook.Add("PlayerSay", "MRP_Handcuffs_GagChat", function(ply, text)
        if ply:GetNWBool("MRP_Gagged", false) then
            ply:ChatPrint("Вы не можете говорить с кляпом во рту.")
            return ""
        end
    end)
    
    -- Sync drag state for visuals
    timer.Create("MRP_Handcuffs_SyncDrag", 0.5, 0, function()
        for _, ply in ipairs(player.GetAll()) do
            if ply.Dragging and IsValid(ply.Dragging) then
                ply:SetNWEntity("MRP_DraggingTarget", ply.Dragging)
            else
                ply:SetNWEntity("MRP_DraggingTarget", NULL)
            end
        end
    end)

    -- Interaction Menu and Move/Freeze logic
    net.Receive("MRP_Handcuffs_DoInteract", function(len, ply)
        -- Removing privilege check to allow anyone with weapon to interact
        -- if ply.IsRHCWhitelisted and not ply:IsRHCWhitelisted() and not ply:IsAdmin() then return end
        
        local target = net.ReadEntity()
        local action = net.ReadString()
        if not IsValid(target) or not target:IsPlayer() or not target:GetNWBool("rhc_cuffed", false) then return end
        if target:GetPos():DistToSqr(ply:GetPos()) > 100000 then return end
        
        if action == "gag" then
            local isGagged = target:GetNWBool("MRP_Gagged", false)
            target:SetNWBool("MRP_Gagged", not isGagged)
            ply:ChatPrint(target:Nick() .. " теперь " .. (not isGagged and "с кляпом" or "без кляпа") .. ".")
        elseif action == "blind" then
            local isBlind = target:GetNWBool("MRP_Blindfolded", false)
            target:SetNWBool("MRP_Blindfolded", not isBlind)
            if not isBlind then target:PrintMessage(HUD_PRINTCENTER, "Вам завязали глаза.") end
            ply:ChatPrint(target:Nick() .. " теперь " .. (not isBlind and "с завязанными глазами" or "без повязки на глазах") .. ".")
        end
    end)

    hook.Add("KeyPress", "MRP_Handcuffs_MoveBind", function(ply, key)
        if key == IN_USE then
            -- Removing privilege check to allow anyone with weapon to interact
            -- if ply.IsRHCWhitelisted and not ply:IsRHCWhitelisted() and not ply:IsAdmin() then return end
            
            local target = GetTarget(ply)
            if IsValid(target) and target:GetNWBool("rhc_cuffed", false) then
                if ply:KeyDown(IN_WALK) then -- ALT + E
                    if target:GetMoveType() == MOVETYPE_NONE then
                        target:SetMoveType(MOVETYPE_WALK)
                        ply:ChatPrint("Разморожен " .. target:Nick())
                    else
                        target:SetMoveType(MOVETYPE_NONE)
                        local trace = util.QuickTrace(ply:EyePos(), ply:GetAimVector() * 80, {ply, target})
                        target:SetPos(trace.HitPos)
                        ply:ChatPrint("Заморожен и перемещен " .. target:Nick())
                    end
                else -- Just E
                    net.Start("MRP_Handcuffs_OpenInteract")
                    net.WriteEntity(target)
                    net.WriteBool(target:GetNWBool("MRP_Gagged", false))
                    net.WriteBool(target:GetNWBool("MRP_Blindfolded", false))
                    net.Send(ply)
                end
            end
        end
    end)

    -- Custom Jailer network receiver
    net.Receive("MRP_Handcuffs_PerformJail", function(len, ply)
        local dragged = net.ReadEntity()
        local time = net.ReadUInt(32) -- up to 3600
        local reason = net.ReadString()
        local cellIndex = net.ReadUInt(8) -- 1, 2, or 3
        
        -- validate
        if not ply.LastJailerNPC or not IsValid(ply.LastJailerNPC) then return end
        if ply:GetPos():DistToSqr(ply.LastJailerNPC:GetPos()) > 60000 then return end
        
        local faction = ply.LastJailerFaction or "RF"
        if not IsValid(dragged) or not dragged:IsPlayer() then return end
        
        -- Validate distance
        if dragged:GetPos():DistToSqr(ply:GetPos()) > 60000 then
            ply:ChatPrint("Заключенный слишком далеко!")
            return
        end
        
        time = math.Clamp(time, 1, 3600)
        
        -- Force teleport to custom cell
        if cellIndex >= 1 and cellIndex <= 3 and MRP_JailCells[faction] and MRP_JailCells[faction][cellIndex] then
            ply:ChatPrint("Игрок " .. dragged:Nick() .. " (" .. dragged:SteamID() .. ") посажен в камеру " .. faction .. " на " .. time .. " сек. Причина: " .. reason)
            
            -- Log the jailing
            hook.Run("RHC_jailed", dragged, ply, time, reason)
            
            -- Keep them cuffed in jail (weapon limits already applied by standalone logic)
            timer.Simple(0.2, function()
                if IsValid(dragged) then
                    dragged:SetPos(MRP_JailCells[faction][cellIndex])
                    
                    if dragged.getChar and dragged:getChar() then
                        dragged:getChar():setData("mrp_jail_time", os.time() + time)
                        dragged:getChar():setData("mrp_jail_faction", faction)
                        dragged:getChar():setData("mrp_jail_cell", cellIndex)
                        dragged:getChar():setData("mrp_jail_reason", reason)
                        dragged:getChar():setData("mrp_jailer_name", ply:Nick())
                        dragged:getChar():setData("mrp_jailer_steam", ply:SteamID())
                        
                        -- Sync to client
                        dragged:SetNWInt("MRP_JailTime", os.time() + time)
                        dragged:SetNWString("MRP_JailReason", reason)
                        dragged:SetNWString("MRP_JailerName", ply:Nick())
                        dragged:SetNWString("MRP_JailerSteam", ply:SteamID())
                        
                        net.Start("MRP_UpdateJailInfo")
                        net.WriteEntity(dragged)
                        net.WriteInt(os.time() + time)
                        net.WriteString(reason)
                        net.WriteString(ply:Nick())
                        net.WriteString(ply:SteamID())
                        net.Broadcast()
                    end
                    
                    -- Simple arrest unjail timer
                    local timerName = "MRP_Jail_" .. dragged:SteamID64()
                    timer.Create(timerName, time, 1, function()
                        if IsValid(dragged) then
                            dragged:Spawn()
                            -- Trigger uncuff manually
                            dragged:SetNWBool("rhc_cuffed", false)
                            dragged:SetNWBool("MRP_Gagged", false)
                            dragged:SetNWBool("MRP_Blindfolded", false)

                            dragged:StripWeapon("weapon_r_cuffed")
                            
                            -- Explicitly reset bone angles
                            local CuffedBones = {
                                ["ValveBiped.Bip01_R_UpperArm"] = true,
                                ["ValveBiped.Bip01_L_UpperArm"] = true,
                                ["ValveBiped.Bip01_R_Forearm"] = true,
                                ["ValveBiped.Bip01_L_Forearm"] = true,
                                ["ValveBiped.Bip01_R_Hand"] = true,
                                ["ValveBiped.Bip01_L_Hand"] = true,
                            }
                            for boneName, _ in pairs(CuffedBones) do
                                local boneId = dragged:LookupBone(boneName)
                                if boneId then
                                    dragged:ManipulateBoneAngles(boneId, Angle(0,0,0))
                                end
                            end

                            if dragged.RHC_SavedWeapons then
                                for _, class in ipairs(dragged.RHC_SavedWeapons) do
                                    dragged:Give(class)
                                end
                                dragged.RHC_SavedWeapons = nil
                            end

                            if dragged.RHC_OldWalk then
                                dragged:SetWalkSpeed(dragged.RHC_OldWalk)
                                dragged:SetRunSpeed(dragged.RHC_OldRun)
                                dragged.RHC_OldWalk = nil
                                dragged.RHC_OldRun = nil
                            end
                            
                            if dragged.getChar and dragged:getChar() then
                                dragged:getChar():setData("mrp_jail_time", nil)
                                dragged:getChar():setData("mrp_jail_faction", nil)
                                dragged:getChar():setData("mrp_jail_cell", nil)
                                dragged:getChar():setData("mrp_jail_reason", nil)
                                dragged:getChar():setData("mrp_jailer_name", nil)
                                dragged:getChar():setData("mrp_jailer_steam", nil)
                                
                                dragged:SetNWInt("MRP_JailTime", 0)
                                dragged:SetNWString("MRP_JailReason", "")
                                dragged:SetNWString("MRP_JailerName", "")
                                dragged:SetNWString("MRP_JailerSteam", "")
                                
                                net.Start("MRP_UpdateJailInfo")
                                net.WriteEntity(dragged)
                                net.WriteInt(0)
                                net.WriteString("")
                                net.WriteString("")
                                net.WriteString("")
                                net.Broadcast()
                            end
                            
                            if dragged.RHC_SavedWeapons then
                                for _, class in ipairs(dragged.RHC_SavedWeapons) do dragged:Give(class) end
                                dragged.RHC_SavedWeapons = nil
                            end
                            if dragged.RHC_OldWalk then
                                dragged:SetWalkSpeed(dragged.RHC_OldWalk)
                                dragged:SetRunSpeed(dragged.RHC_OldRun)
                            end
                            dragged:ChatPrint("Ваш срок заключения подошел к концу.")
                        end
                    end)
                end
            end)
            
            -- Drop drag
            ply.Dragging = nil
            dragged.DraggedBy = nil
            ply:SetNWEntity("MRP_DraggingTarget", NULL)
        else
            ply:ChatPrint("Внимание: Позиция выбранной камеры не настроена! Администратор должен использовать /setcell" .. string.lower(faction) .. " " .. cellIndex)
        end
    end)
    
    
    net.Receive("MRP_Handcuffs_PerformUnjail", function(len, ply)
        local target = net.ReadEntity()
        if not IsValid(target) or not target:IsPlayer() then return end
        
        -- validate
        if not ply.LastJailerNPC or not IsValid(ply.LastJailerNPC) then return end
        if ply:GetPos():DistToSqr(ply.LastJailerNPC:GetPos()) > 60000 then return end
        
        local timerName = "MRP_Jail_" .. target:SteamID64()
        if timer.Exists(timerName) then
            timer.Remove(timerName)
            
            target:SetNWBool("rhc_cuffed", false)
            target:SetNWBool("MRP_Gagged", false)
            target:SetNWBool("MRP_Blindfolded", false)

            target:StripWeapon("weapon_r_cuffed")
            
            -- Explicitly reset bone angles
            local CuffedBones = {
                ["ValveBiped.Bip01_R_UpperArm"] = true,
                ["ValveBiped.Bip01_L_UpperArm"] = true,
                ["ValveBiped.Bip01_R_Forearm"] = true,
                ["ValveBiped.Bip01_L_Forearm"] = true,
                ["ValveBiped.Bip01_R_Hand"] = true,
                ["ValveBiped.Bip01_L_Hand"] = true,
            }
            for boneName, _ in pairs(CuffedBones) do
                local boneId = target:LookupBone(boneName)
                if boneId then
                    target:ManipulateBoneAngles(boneId, Angle(0,0,0))
                end
            end

            if target.RHC_SavedWeapons then
                for _, class in ipairs(target.RHC_SavedWeapons) do
                    target:Give(class)
                end
                target.RHC_SavedWeapons = nil
            end

            if target.RHC_OldWalk then
                target:SetWalkSpeed(target.RHC_OldWalk)
                target:SetRunSpeed(target.RHC_OldRun)
                target.RHC_OldWalk = nil
                target.RHC_OldRun = nil
            end
            
            if target.getChar and target:getChar() then
                target:getChar():setData("mrp_jail_time", nil)
                target:getChar():setData("mrp_jail_faction", nil)
                target:getChar():setData("mrp_jail_cell", nil)
            end
            
            -- Spawn the player naturally, just like after natural timeout
            target:Spawn()
            
            target:ChatPrint("Вас досрочно освободил " .. ply:Nick())
            ply:ChatPrint("Вы освободили " .. target:Nick())
        else
            ply:ChatPrint("Похоже, этот игрок не в тюрьме.")
        end
    end)
    
    -- Reconnect persistence
    hook.Add("PlayerLoadedCharacter", "MRP_Handcuffs_LoadJail", function(ply, character, oldCharacter)
        timer.Simple(1, function()
            if not IsValid(ply) then return end
            if not character or not character.getData then return end  -- FIX

            local jailTime = character:getData("mrp_jail_time", 0)
            local faction = character:getData("mrp_jail_faction", "RF")
            local cellIndex = character:getData("mrp_jail_cell", 1)
            
            if jailTime > os.time() then
                local remaining = jailTime - os.time()
                
                -- Ensure they're cuffed
                ply:SetNWBool("rhc_cuffed", true)
                ply:Give("weapon_r_cuffed")
                
                if MRP_JailCells[faction] and MRP_JailCells[faction][cellIndex] then
                    ply:SetPos(MRP_JailCells[faction][cellIndex])
                end
                
                ply:ChatPrint("Вы вернулись, чтобы отсидеть оставшиеся " .. remaining .. " секунд вашего срока.")
                
                -- Sync jail info to client
                ply:SetNWInt("MRP_JailTime", jailTime)
                ply:SetNWString("MRP_JailReason", character:getData("mrp_jail_reason", "Не указана"))
                ply:SetNWString("MRP_JailerName", character:getData("mrp_jailer_name", "Неизвестен"))
                ply:SetNWString("MRP_JailerSteam", character:getData("mrp_jailer_steam", "Неизвестен"))
                
                net.Start("MRP_UpdateJailInfo")
                net.WriteEntity(ply)
                net.WriteInt(jailTime)
                net.WriteString(character:getData("mrp_jail_reason", "Не указана"))
                net.WriteString(character:getData("mrp_jailer_name", "Неизвестен"))
                net.WriteString(character:getData("mrp_jailer_steam", "Неизвестен"))
                net.Broadcast()
                
                -- Re-apply timer
                local timerName = "MRP_Jail_" .. ply:SteamID64()
                timer.Create(timerName, remaining, 1, function()
                    if IsValid(ply) then
                        ply:SetNWBool("rhc_cuffed", false)
                        ply:SetNWBool("MRP_Gagged", false)
                        ply:SetNWBool("MRP_Blindfolded", false)
                        ply:StripWeapon("weapon_r_cuffed")
                        if ply.getChar and ply:getChar() then
                            ply:getChar():setData("mrp_jail_time", nil)
                            ply:getChar():setData("mrp_jail_faction", nil)
                            ply:getChar():setData("mrp_jail_cell", nil)
                        end
                        
                        -- Look for nearest appropriate jailer for un-jailing position
                        local classStr = (faction == "RF") and "rhc_jailer_rf" or "rhc_jailer_uk"
                        local npc = ents.FindByClass(classStr)[1]
                        if IsValid(npc) then
                            ply:Spawn()
                        end
                        
                        ply:ChatPrint("Ваш срок заключения подошел к концу.")
                    end
                end)
            else
                -- Timed out while offline or was free
                if character:getData("mrp_jail_time") then
                    character:setData("mrp_jail_time", nil)
                    character:setData("mrp_jail_faction", nil)
                    character:setData("mrp_jail_cell", nil)
                    character:setData("mrp_jail_reason", nil)
                    character:setData("mrp_jailer_name", nil)
                    character:setData("mrp_jailer_steam", nil)
                    
                    ply:SetNWInt("MRP_JailTime", 0)
                    ply:SetNWString("MRP_JailReason", "")
                    ply:SetNWString("MRP_JailerName", "")
                    ply:SetNWString("MRP_JailerSteam", "")
                    
                    net.Start("MRP_UpdateJailInfo")
                    net.WriteEntity(ply)
                    net.WriteInt(0)
                    net.WriteString("")
                    net.WriteString("")
                    net.WriteString("")
                    net.Broadcast()
                end
            end
        end)
    end)
    
    -- Reset cuff state on spawn if not jailed
    hook.Add("PlayerSpawn", "MRP_Handcuffs_ResetOnSpawn", function(ply)
        if ply:GetNWBool("rhc_cuffed", false) then
            local character = ply.getChar and ply:getChar()
            if not character or not character.getData or character:getData("mrp_jail_time", 0) <= os.time() then
                -- Not jailed, reset cuff state
                ply:SetNWBool("rhc_cuffed", false)
                ply:SetNWBool("MRP_Gagged", false)
                ply:SetNWBool("MRP_Blindfolded", false)
                ply:StripWeapon("weapon_r_cuffed")
                
                -- Reset bones
                for boneName, _ in pairs({
                    ["ValveBiped.Bip01_R_UpperArm"] = true,
                    ["ValveBiped.Bip01_L_UpperArm"] = true,
                    ["ValveBiped.Bip01_R_Forearm"] = true,
                    ["ValveBiped.Bip01_L_Forearm"] = true,
                    ["ValveBiped.Bip01_R_Hand"] = true,
                    ["ValveBiped.Bip01_L_Hand"] = true,
                }) do
                    local boneId = ply:LookupBone(boneName)
                    if boneId then
                        ply:ManipulateBoneAngles(boneId, Angle(0,0,0))
                    end
                end
                
                -- Restore weapons and speed if saved
                if ply.RHC_SavedWeapons then
                    for _, class in ipairs(ply.RHC_SavedWeapons) do
                        ply:Give(class)
                    end
                    ply.RHC_SavedWeapons = nil
                end
                if ply.RHC_OldWalk then
                    ply:SetWalkSpeed(ply.RHC_OldWalk)
                    ply:SetRunSpeed(ply.RHC_OldRun)
                    ply.RHC_OldWalk = nil
                    ply.RHC_OldRun = nil
                end
            end
        end
    end)
    
end

if CLIENT then
    local clientJailTime = 0
    local clientJailReason = ""
    local clientJailerName = ""
    local clientJailerSteam = ""
    
    net.Receive("MRP_UpdateJailInfo", function()
        local ent = net.ReadEntity()
        if ent == LocalPlayer() then
            clientJailTime = net.ReadInt()
            clientJailReason = net.ReadString()
            clientJailerName = net.ReadString()
            clientJailerSteam = net.ReadString()
        end
    end)
    -- Blindfold Overlay
    hook.Add("HUDPaint", "MRP_Handcuffs_BlindfoldHUD", function()
        local ply = LocalPlayer()
        if not IsValid(ply) then return end
        if ply:GetNWBool("MRP_Blindfolded", false) then
            surface.SetDrawColor(0, 0, 0, 255)
            surface.DrawRect(0, 0, ScrW(), ScrH())
            draw.SimpleText("У вас завязаны глаза", "Trebuchet24", ScrW()/2, ScrH()/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
        end
    end)

    -- Jail Time HUD
    hook.Add("HUDPaint", "MRP_Handcuffs_JailHUD", function()
        if clientJailTime > os.time() then
            local remaining = clientJailTime - os.time()
            local minutes = math.floor(remaining / 60)
            local seconds = remaining % 60
            local timeStr = string.format("%02d:%02d", minutes, seconds)
            
            draw.SimpleTextOutlined("Осталось сидеть: " .. timeStr, "Trebuchet24", ScrW()/2, ScrH() - 150, Color(255, 255, 100, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 2, Color(0, 0, 0, 255))
            
            draw.SimpleTextOutlined("Причина: " .. clientJailReason, "Trebuchet18", ScrW()/2, ScrH() - 120, Color(255, 255, 100, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 2, Color(0, 0, 0, 255))
            
            draw.SimpleTextOutlined("Посадил: " .. clientJailerName .. " (" .. clientJailerSteam .. ")", "Trebuchet18", ScrW()/2, ScrH() - 90, Color(255, 255, 100, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 2, Color(0, 0, 0, 255))
        end
    end)

    -- Beam dragging visual 
    local matBeam = Material("cable/rope")
    hook.Add("PostDrawTranslucentRenderables", "MRP_Handcuffs_DrawDrag", function()
        for _, ply in ipairs(player.GetAll()) do
            local target = ply:GetNWEntity("MRP_DraggingTarget")
            if IsValid(target) then
                local startPos = ply:GetPos() + Vector(0,0,40)
                local endPos = target:GetPos() + Vector(0,0,40)
                
                local wep = ply:GetActiveWeapon()
                if IsValid(wep) then
                    local vm = ply:GetViewModel()
                    if ply == LocalPlayer() and not ply:ShouldDrawLocalPlayer() and IsValid(vm) then
                        local attach = vm:GetAttachment(1)
                        if attach then startPos = attach.Pos end
                    else
                        local attach = wep:GetAttachment(1)
                        if attach then 
                            startPos = attach.Pos 
                        else 
                            local bone = ply:LookupBone("ValveBiped.Bip01_R_Hand")
                            if bone then
                                local bPos = ply:GetBonePosition(bone)
                                if bPos then startPos = bPos end
                            end
                        end
                    end
                else
                    local bone = ply:LookupBone("ValveBiped.Bip01_R_Hand")
                    if bone then
                        local bPos = ply:GetBonePosition(bone)
                        if bPos then startPos = bPos end
                    end
                end
                
                local tBone = target:LookupBone("ValveBiped.Bip01_R_Hand")
                if tBone then
                    local bPos = target:GetBonePosition(tBone)
                    if bPos then endPos = bPos end
                end
                
                render.SetMaterial(matBeam)
                render.DrawBeam(startPos, endPos, 2, 0, startPos:Distance(endPos) / 10, color_white)
            end
        end
    end)
    
    -- Models
    hook.Add("PostPlayerDraw", "MRP_Handcuffs_DrawModels", function(ply)
        if not IsValid(ply) or not ply:Alive() then return end
        
        local isGagged = ply:GetNWBool("MRP_Gagged", false)
        local isBlind = ply:GetNWBool("MRP_Blindfolded", false)
        
        if not isGagged and not isBlind then return end
        
        local bone = ply:LookupBone("ValveBiped.Bip01_Head1")
        if not bone then return end
        
        local pos, ang = ply:GetBonePosition(bone)
        if not pos or not ang then return end

        if isGagged then
            if not IsValid(gagModel) then
                gagModel = ClientsideModel("models/kidnappers_kit/tape gag cross/tapegagcross.mdl")
                if IsValid(gagModel) then gagModel:SetNoDraw(true) end
            end
            
            if IsValid(gagModel) then
                local gagAng = ang * 1
                gagAng:RotateAroundAxis(gagAng:Right(), -92.67)
                gagAng:RotateAroundAxis(gagAng:Up(), -85.54)
                gagAng:RotateAroundAxis(gagAng:Forward(), 0)
                
                local offset = ang:Forward() * -59.4 + ang:Right() * 6.53 + ang:Up() * 2.77
                
                gagModel:SetRenderOrigin(pos + offset)
                gagModel:SetRenderAngles(gagAng)
                gagModel:SetModelScale(1)
                gagModel:DrawModel()
            end
        end
        
        if isBlind then
            if not IsValid(blindModel) then
                blindModel = ClientsideModel("models/kidnappers_kit/tape blindfold/tapeblindfold.mdl")
                if IsValid(blindModel) then blindModel:SetNoDraw(true) end
            end
            
            if IsValid(blindModel) then
                local blindAng = ang * 1
                blindAng:RotateAroundAxis(blindAng:Right(), -90)
                blindAng:RotateAroundAxis(blindAng:Up(), -89.11)
                blindAng:RotateAroundAxis(blindAng:Forward(), 0)
                
                local offset = ang:Forward() * -49 + ang:Right() * 3.17 + ang:Up() * 0.4
                
                blindModel:SetRenderOrigin(pos + offset)
                blindModel:SetRenderAngles(blindAng)
                blindModel:SetModelScale(0.92)
                blindModel:DrawModel()
            end
        end
    end)

    timer.Simple(2, function()
        net.Receive("RHC_Jailer_Menu", function()
            local dragged = net.ReadEntity()
            local faction = net.ReadString() -- "RF" or "UK"
            if not IsValid(dragged) then
                chat.AddText(Color(255,0,0), "Рядом нет закованных игроков!")
                return
            end
            
            local factionTitle = (faction == "RF" or faction == "UK") and (" (" .. faction .. ")") or ""
            
            local frame = vgui.Create("DFrame")
            frame:SetSize(400, 320)
            frame:Center()
            frame:SetTitle("Посадить игрока: " .. dragged:Nick() .. factionTitle)
            frame:MakePopup()
            frame.Paint = function(self, w, h)
                draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 240))
                draw.RoundedBox(4, 0, 0, w, 24, Color(30, 30, 30, 255))
            end
            
            local timeLabel = vgui.Create("DLabel", frame)
            timeLabel:SetPos(20, 40)
            timeLabel:SetText("Время (1-3600 сек):")
            timeLabel:SizeToContents()
            timeLabel:SetTextColor(color_white)
            
            local timeText = vgui.Create("DTextEntry", frame)
            timeText:SetPos(20, 60)
            timeText:SetSize(360, 25)
            timeText:SetText("300")
            timeText:SetNumeric(true)
            
            local reasonLabel = vgui.Create("DLabel", frame)
            reasonLabel:SetPos(20, 100)
            reasonLabel:SetText("Причина:")
            reasonLabel:SizeToContents()
            reasonLabel:SetTextColor(color_white)
            
            local reasonText = vgui.Create("DTextEntry", frame)
            reasonText:SetPos(20, 120)
            reasonText:SetSize(360, 25)
            reasonText:SetText("Причина не указана")
            
            local cellLabel = vgui.Create("DLabel", frame)
            cellLabel:SetPos(20, 160)
            cellLabel:SetText("Выберите камеру:")
            cellLabel:SizeToContents()
            cellLabel:SetTextColor(color_white)
            
            local cellCombo = vgui.Create("DComboBox", frame)
            cellCombo:SetPos(20, 180)
            cellCombo:SetSize(360, 25)
            cellCombo:SetValue("Камера 1")
            cellCombo:AddChoice("Камера 1", 1)
            cellCombo:AddChoice("Камера 2", 2)
            cellCombo:AddChoice("Камера 3", 3)
            
            local submitBtn = vgui.Create("DButton", frame)
            submitBtn:SetPos(20, 230)
            submitBtn:SetSize(360, 40)
            submitBtn:SetText("Посадить")
            submitBtn:SetTextColor(color_white)
            submitBtn.Paint = function(self, w, h)
                local col = self:IsHovered() and Color(60, 120, 200) or Color(50, 100, 180)
                draw.RoundedBox(4, 0, 0, w, h, col)
            end
            submitBtn.DoClick = function()
                local time = tonumber(timeText:GetValue()) or 300
                local reason = reasonText:GetValue()
                local _, cellIndex = cellCombo:GetSelected()
                cellIndex = cellIndex or 1
                
                net.Start("MRP_Handcuffs_PerformJail")
                net.WriteEntity(dragged)
                net.WriteUInt(time, 32)
                net.WriteString(reason)
                net.WriteUInt(cellIndex, 8)
                net.SendToServer()
                
                frame:Close()
            end
            
            -- Unjail functionality
            local unjailBtn = vgui.Create("DButton", frame)
            unjailBtn:SetPos(20, 275)
            unjailBtn:SetSize(360, 25)
            unjailBtn:SetText("Показать список заключенных для освобождения")
            unjailBtn:SetTextColor(Color(255,100,100))
            unjailBtn.Paint = function(self, w, h)
                draw.RoundedBox(4, 0, 0, w, h, Color(50, 20, 20))
            end
            
            unjailBtn.DoClick = function()
                frame:Close()
                
                local uFrame = vgui.Create("DFrame")
                uFrame:SetSize(300, 400)
                uFrame:Center()
                uFrame:SetTitle("Досрочное освобождение")
                uFrame:MakePopup()
                uFrame.Paint = function(self, w, h)
                    draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 240))
                end
                
                local list = vgui.Create("DListView", uFrame)
                list:Dock(FILL)
                list:AddColumn("Заключенные игроки")
                
                for _, p in ipairs(player.GetAll()) do
                    if p:GetNWBool("rhc_cuffed", false) and not IsValid(p.DraggedBy) then
                        local line = list:AddLine(p:Nick())
                        line.PlayerObj = p
                    end
                end
                
                local relBtn = vgui.Create("DButton", uFrame)
                relBtn:Dock(BOTTOM)
                relBtn:SetTall(30)
                relBtn:SetText("Освободить выбранного")
                relBtn.DoClick = function()
                    local selected = list:GetSelectedLine()
                    if selected then
                        local plyObj = list:GetLine(selected).PlayerObj
                        if IsValid(plyObj) then
                            net.Start("MRP_Handcuffs_PerformUnjail")
                            net.WriteEntity(plyObj)
                            net.SendToServer()
                        end
                        uFrame:Close()
                    end
                end
            end
        end)
    end)

    net.Receive("MRP_Handcuffs_OpenInteract", function()
        local target = net.ReadEntity()
        local isGagged = net.ReadBool()
        local isBlind = net.ReadBool()
        
        if not IsValid(target) then return end
        
        local frame = vgui.Create("DFrame")
        frame:SetSize(250, 140)
        frame:Center()
        frame:SetTitle("Взаимодействие: " .. target:Nick())
        frame:MakePopup()
        frame.Paint = function(self, w, h)
            draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 240))
            draw.RoundedBox(4, 0, 0, w, 24, Color(30, 30, 30, 255))
        end
        
        local gagBtn = vgui.Create("DButton", frame)
        gagBtn:Dock(TOP)
        gagBtn:DockMargin(10, 10, 10, 0)
        gagBtn:SetTall(35)
        gagBtn:SetText(isGagged and "Снять кляп" or "Вставить кляп")
        gagBtn:SetTextColor(color_white)
        gagBtn.Paint = function(self, w, h)
            draw.RoundedBox(4, 0, 0, w, h, self:IsHovered() and Color(60, 60, 60) or Color(80, 80, 80))
        end
        gagBtn.DoClick = function()
            net.Start("MRP_Handcuffs_DoInteract")
            net.WriteEntity(target)
            net.WriteString("gag")
            net.SendToServer()
            frame:Close()
        end
        
        local blindBtn = vgui.Create("DButton", frame)
        blindBtn:Dock(TOP)
        blindBtn:DockMargin(10, 10, 10, 0)
        blindBtn:SetTall(35)
        blindBtn:SetText(isBlind and "Снять повязку" or "Надеть повязку")
        blindBtn:SetTextColor(color_white)
        blindBtn.Paint = function(self, w, h)
            draw.RoundedBox(4, 0, 0, w, h, self:IsHovered() and Color(60, 60, 60) or Color(80, 80, 80))
        end
        blindBtn.DoClick = function()
            net.Start("MRP_Handcuffs_DoInteract")
            net.WriteEntity(target)
            net.WriteString("blind")
            net.SendToServer()
            frame:Close()
        end
    end)
end
