local rails = {
    { "elevated-curved-rail-a",      "hidden-elevated-curved-rail-a" },
    { "elevated-curved-rail-b",      "hidden-elevated-curved-rail-b" },
    { "elevated-straight-rail",      "hidden-elevated-straight-rail" },
    { "elevated-half-diagonal-rail", "hidden-elevated-half-diagonal-rail" },
    { "rail-support",                "hidden-rail-support" },
    { "rail-ramp",                   "hidden-rail-ramp" }
}

function toggle_elevated_rails(event)
    local hidden = storage.player_hidden_setting[event.player_index]
    local player = game.players[event.player_index]
    if hidden then
        player.create_local_flying_text { text = "Elevated rails are now shown!", position = { player.position.x, player.position.y - 2 } }
        player.set_shortcut_toggled("toggle-elevated-rails", true)
        hidden = false
    else
        player.create_local_flying_text { text = "Elevated rails are now hidden!", position = { player.position.x, player.position.y - 2 } }
        player.set_shortcut_toggled("toggle-elevated-rails", false)
        hidden = true
    end
    player.play_sound { path = "utility/console_message" }

    storage.player_hidden_setting[event.player_index] = hidden
end

function replace(surface, entity, replacement, forced)
    -- Only if there are no trains in this rail segment's block

    if not string.find(entity.name, "support") then
        if entity.trains_in_block > 0 then
            return
        end
    end

    local name = replacement
    local pos = entity.position
    local dir = entity.direction
    local q = entity.quality
    local f = entity.force
    local decon = entity.to_be_deconstructed()
    entity.destroy()

    local new = surface.create_entity {
        name = name,
        position = pos,
        direction = dir,
        quality = q,
        force = f,
        create_build_effect_smoke = false,

    }
    if decon then
        new.order_deconstruction(f)
    end
end

function remove_hidden_rails()
    local surfaces = game.surfaces
    for i, s in pairs(surfaces) do
        for x, rail in pairs(rails) do
            local entities = s.find_entities_filtered { name = rail[2] }
            for _, entity in pairs(entities) do
                replace(entity.surface, entity, rail[1], true)
            end
        end
    end
end

script.on_event("hide-elevated-rails",
    function(event)
        toggle_elevated_rails(event)
    end
)

script.on_event("on_lua_shortcut",
    function(event)
        if event.prototype_name == "toggle-elevated-rails" then
            toggle_elevated_rails(event)
        end
    end
)

script.on_event("force-reset-elevated-rails",
    function(event)
        remove_hidden_rails()
        local player = game.players[event.player_index]
        storage.player_hidden_setting[event.player_index] = false
        game.players[event.player_index].create_local_flying_text { text = "Force shown all elevated rails!", position = { player.position.x, player.position.y - 2 } }
        player.play_sound { path = "utility/console_message" }
        player.set_shortcut_toggled("toggle-elevated-rails", true)
    end
)

local function init()
    storage.player_hidden_setting = {}
    storage.tick_delay_10 = 0
end

script.on_init(init)
script.on_configuration_changed(init)

script.on_nth_tick(10,
    function(event)
        for i, local_player in pairs(game.players) do
            if local_player.render_mode == 3 or local_player.render_mode == 1 then
                if storage.player_hidden_setting[i] == nil then
                    storage.player_hidden_setting[i] = false
                    local_player.set_shortcut_toggled("toggle-elevated-rails", true)
                end

                local should_switch_rails = true
                local s = local_player.surface

                if not storage.player_hidden_setting[i] then
                    for o, other_player in pairs(game.players) do
                        -- Only run when the player is not the current player
                        if o ~= i then
                            local loc_x = local_player.position.x
                            local loc_y = local_player.position.y
                            local oth_x = other_player.position.x
                            local oth_y = other_player.position.y
                            local dist = math.sqrt((loc_x - oth_x) ^ 2 + (loc_y - oth_y) ^ 2)
                            if dist < 32 and storage.player_hidden_setting[o] then
                                should_switch_rails = false
                            end
                        end
                    end
                end

                if should_switch_rails then
                    for _, rail in pairs(rails) do
                        if storage.player_hidden_setting[i] then
                            local entities = s.find_entities_filtered { name = rail[1], position = local_player.position, radius = 16 }
                            for _, entity in pairs(entities) do
                                replace(entity.surface, entity, rail[2], false)
                            end
                        else
                            local entities = s.find_entities_filtered { name = rail[2], position = local_player.position, radius = 16 }
                            for _, entity in pairs(entities) do
                                replace(entity.surface, entity, rail[1], false)
                            end
                        end
                    end
                end
            end
        end
    end
)


--[[

find_entities_filtered(filter)

https://lua-api.factorio.com/latest/classes/LuaSurface.html#create_entity

]]
