```lua
-- Server-side constants and settings
if SERVER then
    local SANITY_MAX = 100
    local JUMPSCARE_COOLDOWN = 30
    local HALLUCINATION_INTERVAL = 10

    -- Define network strings
    util.AddNetworkString("FearOfDark_UpdateDarkness")
    util.AddNetworkString("FearOfDark_StageChange")
    util.AddNetworkString("FearOfDark_ParanoiaMessage")
    util.AddNetworkString("FearOfDark_JumpScare")

    -- Initialize player sanity and related variables
    local function InitializePlayer(ply)
        ply.Sanity = SANITY_MAX
        ply:SetNWFloat("Sanity", SANITY_MAX)
        ply.LastSanityStage = 5
        ply.InDarkness = false
        ply.LastJumpScareTime = 0
    end
    hook.Add("PlayerInitialSpawn", "FearOfDark_InitSanity", InitializePlayer)

    -- Update player sanity based on darkness state
    local function UpdateSanity(ply)
        if not ply:Alive() then return end
        local sanity = ply:GetNWFloat("Sanity", SANITY_MAX)
        local delta = FrameTime()
        if ply.InDarkness then
            local loss = ply:FlashlightIsOn() and 0.5 or 1
            sanity = math.max(sanity - loss * delta, 0)
        else
            sanity = math.min(sanity + 0.5 * delta, SANITY_MAX)
        end

        ply:SetNWFloat("Sanity", sanity)
        local new_stage = math.ceil(sanity / 20)
        if new_stage ~= ply.LastSanityStage then
            ply.LastSanityStage = new_stage
            net.Start("FearOfDark_StageChange")
            net.WriteUInt(new_stage, 3)
            net.Send(ply)
        end
    end

    -- Trigger jumpscares for low sanity players
    local function TryJumpscare(ply)
        local sanity = ply:GetNWFloat("Sanity", SANITY_MAX)
        if sanity >= 10 then return end
        if CurTime() - ply.LastJumpScareTime < JUMPSCARE_COOLDOWN then return end
        if math.random() > 0.005 then return end
        ply.LastJumpScareTime = CurTime()
        net.Start("FearOfDark_JumpScare")
        net.Send(ply)
    end

    -- Play hallucination sounds and send paranoia messages
    local HALLUCINATION_SOUNDS = {
        {sound = "ambient/levels/canals/windchime2.wav", pitch = 90, volume = 0.8},
        {sound = "npc/footsteps/hardboot_generic1.wav", pitch = 80, volume = 0.8},
        {sound = "npc/footsteps/hardboot_generic2.wav", pitch = 80, volume = 0.8}
    }

    local function PlayHallucinations()
        for _, ply in ipairs(player.GetAll()) do
            if not ply:Alive() or ply:GetNWFloat("Sanity", SANITY_MAX) >= 40 then continue end
            local pos = ply:GetPos() + VectorRand() * 200
            local sound_data = HALLUCINATION_SOUNDS[math.random(#HALLUCINATION_SOUNDS)]
            sound.Play(sound_data.sound, pos, 75, sound_data.pitch, sound_data.volume)
            if ply:GetNWFloat("Sanity", SANITY_MAX) < 20 then
                net.Start("FearOfDark_ParanoiaMessage")
                net.WriteString("Something is watching you...")
                net.Send(ply)
            end
        end
    end
    timer.Create("FearOfDark_HallucinationTimer", HALLUCINATION_INTERVAL, 0, PlayHallucinations)

    -- Main server loop
    hook.Add("Think", "FearOfDark_SanitySystem", function()
        for _, ply in ipairs(player.GetAll()) do
            UpdateSanity(ply)
            TryJumpscare(ply)
        end
    end)

    -- Receive darkness state from client
    net.Receive("FearOfDark_UpdateDarkness", function(_, ply)
        ply.InDarkness = net.ReadBool()
    end)
end

-- Client-side constants and variables
if CLIENT then
    local SANITY_MAX = 100
    local JUMPSCARE_COOLDOWN = 30
    local DARKNESS_CHECK_INTERVAL = 1
    local DEFAULT_FOV = 90

    -- State variables
    local sanity = SANITY_MAX
    local vignetteAlpha = 0
    local hallucinationEnts = {}
    local lastJumpScareTime = 0
    local lastDarknessCheck = 0
    local invertColorsEndTime = 0
    local flickerStartTime = 0
    local flickerEndTime = 0
    local isFOVChanged = false

    -- Handle 2D screen effects (vignette, text, fragmented screen, flicker)
    local function HandleScreenEffects()
        if sanity < 80 then
            vignetteAlpha = math.min((80 - sanity) * 3, 150)
            surface.SetDrawColor(0, 0, 0, vignetteAlpha)
            surface.DrawRect(0, 0, ScrW(), ScrH())
        end

        draw.SimpleText("Sanity: " .. math.floor(sanity), "DermaDefault", 10, 10, Color(255, 255, 255))
        if sanity < 15 then
            draw.SimpleText("Your mind is breaking...", "DermaLarge", ScrW() / 2 - 150, ScrH() / 2, Color(255, 0, 0))
        end

        if CurTime() < flickerEndTime then
            local alpha = math.random(50, 150)
            surface.SetDrawColor(255, 255, 255, alpha)
            surface.DrawRect(0, 0, ScrW(), ScrH())
        end
    end

    -- Handle post-processing effects (color modification, motion blur, screen shake)
    local function HandlePostProcessing()
        if CurTime() < invertColorsEndTime then
            DrawColorModify({
                ["$pp_colour_colour"] = -1,
                ["$pp_colour_brightness"] = 0,
                ["$pp_colour_contrast"] = 1,
                ["$pp_colour_addr"] = 0,
                ["$pp_colour_addg"] = 0,
                ["$pp_colour_addb"] = 0,
            })
        else
            local colMod = {
                ["$pp_colour_addr"] = 0,
                ["$pp_colour_addg"] = 0,
                ["$pp_colour_addb"] = 0,
                ["$pp_colour_brightness"] = 0,
                ["$pp_colour_contrast"] = 1,
                ["$pp_colour_colour"] = 1,
                ["$pp_colour_mulr"] = 0,
                ["$pp_colour_mulg"] = 0,
                ["$pp_colour_mulb"] = 0
            }

            if sanity < 100 then colMod["$pp_colour_addr"] = (100 - sanity) * 0.001 end
            if sanity < 80 then
                colMod["$pp_colour_colour"] = math.max(1 - (80 - sanity) * 0.01, 0.5)
                colMod["$pp_colour_brightness"] = -0.05
                colMod["$pp_colour_contrast"] = 1 + (80 - sanity) * 0.01
            end
            if sanity < 50 then
                colMod["$pp_colour_colour"] = 1 - (50 - sanity) * 0.02
                colMod["$pp_colour_contrast"] = 1 + (50 - sanity) * 0.02
                colMod["$pp_colour_brightness"] = -0.1
            end
            if sanity < 20 then
                colMod["$pp_colour_brightness"] = -0.15
                colMod["$pp_colour_contrast"] = 1.1 + (20 - sanity) * 0.05
                colMod["$pp_colour_colour"] = 1 - (20 - sanity) * 0.05
            end
            DrawColorModify(colMod)
        end

        if sanity < 10 then
            DrawMotionBlur(0.15, 6, 0.05)
        elseif sanity < 40 then
            DrawMotionBlur(0.1, 5, 0.05)
        elseif sanity < 70 then
            DrawMotionBlur(0.05, 4, 0.05)
        end

        local shakeMagnitude = 0
        if sanity < 90 then shakeMagnitude = math.max(shakeMagnitude, (90 - sanity) / 90 * 0.3) end
        if sanity < 60 then shakeMagnitude = math.max(shakeMagnitude, (60 - sanity) / 60 * 0.5) end
        if sanity < 10 then shakeMagnitude = math.max(shakeMagnitude, (10 - sanity) / 10 * 0.8) end
        if shakeMagnitude > 0 then
            util.ScreenShake(LocalPlayer():GetPos(), shakeMagnitude, 5, 0.5, 100)
        end
    end

    -- Create hallucination entities
    local HALLUCINATION_MODELS = {"models/Humans/Group01/male_07.mdl", "models/Humans/Group01/female_07.mdl"}
    local function CreateHallucination()
        if #hallucinationEnts >= 3 then return end
        local ply = LocalPlayer()
        local ent = ClientsideModel(table.Random(HALLUCINATION_MODELS))
        ent:SetPos(ply:GetPos() + Vector(math.random(-300, 300), math.random(-300, 300), 0))
        ent:SetAngles((ply:GetPos() - ent:GetPos()):Angle())
        ent:SetColor(Color(50, 50, 50, sanity < 20 and 200 or 150))
        ent:SetRenderMode(RENDERMODE_TRANSALPHA)
        table.insert(hallucinationEnts, ent)
        timer.Simple(10, function()
            if IsValid(ent) then ent:Remove() end
            table.RemoveByValue(hallucinationEnts, ent)
        end)
    end

    -- Create ghost silhouette entities
    local function CreateGhostSilhouette()
        if #hallucinationEnts >= 3 then return end
        local ply = LocalPlayer()
        local ghost = ClientsideModel("models/Humans/Group01/male_07.mdl")
        ghost:SetPos(ply:GetPos() + Vector(math.random(-400, 400), math.random(-400, 400), 0))
        ghost:SetAngles((ply:GetPos() - ghost:GetPos()):Angle())
        ghost:SetColor(Color(200, 200, 255, 100))
        ghost:SetRenderMode(RENDERMODE_TRANSALPHA)
        table.insert(hallucinationEnts, ghost)
        timer.Simple(8, function()
            if IsValid(ghost) then ghost:Remove() end
            table.RemoveByValue(hallucinationEnts, ghost)
        end)
    end

    -- Update darkness state and send to server
    local function UpdateDarknessState()
        if CurTime() - lastDarknessCheck < DARKNESS_CHECK_INTERVAL then return end
        lastDarknessCheck = CurTime()
        local lightColor = render.GetLightColor(LocalPlayer():GetPos())
        local brightness = (lightColor.x + lightColor.y + lightColor.z) / 3
        net.Start("FearOfDark_UpdateDarkness")
        net.WriteBool(brightness < 0.2)
        net.SendToServer()
    end

    -- Trigger jumpscare effect
    local function TriggerJumpscare()
        if CurTime() - lastJumpScareTime < JUMPSCARE_COOLDOWN then return end
        lastJumpScareTime = CurTime()
        surface.PlaySound("npc/stalker/go_alert2.wav")
        local flashEnd = CurTime() + 0.2
        hook.Add("HUDPaint", "FearOfDark_JumpScareFlash", function()
            if CurTime() < flashEnd then
                surface.SetDrawColor(255, 255, 255, 200)
                surface.DrawRect(0, 0, ScrW(), ScrH())
            else
                hook.Remove("HUDPaint", "FearOfDark_JumpScareFlash")
            end
        end)
    end

    -- Additional effect functions
    local function HandleSoundDistortion()
        local distortedPitch = math.random(70, 130)
        LocalPlayer():EmitSound("npc/stalker/go_alert2.wav", 75, distortedPitch)
    end

    local function DisplayParanoiaMessage(msg)
        chat.AddText(Color(200, 0, 0), msg)
    end

    local function PlaySoundEcho()
        LocalPlayer():EmitSound("npc/strider/creak1.wav", 75, 100)
        timer.Simple(0.3, function()
            LocalPlayer():EmitSound("ambient/levels/streetwar/strider_distant2.wav", 75, 90)
        end)
    end

    -- Network receivers
    net.Receive("FearOfDark_StageChange", function()
        sanity = LocalPlayer():GetNWFloat("Sanity", SANITY_MAX)
    end)
    net.Receive("FearOfDark_ParanoiaMessage", function()
        chat.AddText(Color(150, 0, 0), net.ReadString())
    end)
    net.Receive("FearOfDark_JumpScare", TriggerJumpscare)

    -- Main client loop with effect triggers
    hook.Add("Think", "FearOfDark_ClientThink", function()
        sanity = LocalPlayer():GetNWFloat("Sanity", SANITY_MAX)
        UpdateDarknessState()

        if sanity < 70 and math.random() < 0.02 then
            invertColorsEndTime = CurTime() + math.Rand(0.5, 1.5)
        end
        if sanity < 30 and math.random() < 0.02 then
            flickerStartTime = CurTime()
            flickerEndTime = CurTime() + math.Rand(0.5, 2)
        end
        if sanity < 40 and not isFOVChanged and math.random() < 0.01 then
            local newFOV = DEFAULT_FOV + math.random(-20, 20)
            LocalPlayer():SetFOV(newFOV, 0.2)
            isFOVChanged = true
            timer.Simple(math.Rand(5, 10), function()
                if IsValid(LocalPlayer()) then
                    LocalPlayer():SetFOV(DEFAULT_FOV, 0.2)
                end
                isFOVChanged = false
            end)
        end
        if sanity < 60 and math.random() < 0.05 then
            surface.PlaySound(table.Random({
                "ambient/creatures/town_scared_breathing1.wav",
                "ambient/levels/prison/radio_random1.wav",
                "physics/wood/wood_box_impact_soft2.wav",
                "weapons/fx/tink/shotgun_shell3.wav"
            }))
        end
        if sanity < 50 and math.random() < 0.01 then HandleSoundDistortion() end
        if sanity < 40 and math.random() < 0.02 then CreateHallucination() end
        if sanity < 35 and math.random() < 0.005 then CreateGhostSilhouette() end
        if sanity < 25 and math.random() < 0.01 then DisplayParanoiaMessage("Do you hear the voices?") end
        if sanity < 20 and math.random() < 0.005 then PlaySoundEcho() end
        if sanity < 20 and math.random() < 0.01 then LocalPlayer():SetEyeAngles(AngleRand(-90, 90)) end
    end)

    -- Rendering hooks
    hook.Add("HUDPaint", "FearOfDark_HUDEffects", HandleScreenEffects)
    hook.Add("RenderScreenspaceEffects", "FearOfDark_ScreenEffects", HandlePostProcessing)
end
```
Преобразуй следующий код, чтобы он соответствовал уровню senior-разработчика: используй объектно-ориентированное программирование с инкапсуляцией, абстракцией и наследованием там, где это уместно, сделай архитектуру модульной, расширяемой и поддерживаемой, оптимизируй производительность и читаемость, улучшай именования переменных, функций и классов, устраняй дублирование кода, применяй подходящие паттерны проектирования для гибкости и масштабируемости, внедри обработку ошибок с информативными сообщениями и обеспечь логирование ключевых событий, добавь подробные комментарии и документацию к основным классам и методам, обеспечь финальный код простым для понимания, тестирования и поддержки.