-- Biters, Spawners and Worms gain additional health / resistance -- mewmew
-- Use storage.biter_health_boost or storage.biter_health_boost_forces to modify their health.
-- 1 = vanilla health, 2 = 200% vanilla health
-- do not use values below 1
local math_floor = math.floor
local math_round = math.round
local Public = {}

local entity_types = {
    ['unit'] = true,
    ['turret'] = true,
    ['unit-spawner'] = true
}

if is_loaded('maps.biter_hatchery.terrain') then
    entity_types['unit-spawner'] = nil
end

local function clean_table()
    --Perform a table cleanup every 1000 boosts
    storage.biter_health_boost_count = storage.biter_health_boost_count + 1
    if storage.biter_health_boost_count % 1000 ~= 0 then
        return
    end

    local units_to_delete = {}

    --Mark all health boost entries for deletion
    for key, _ in pairs(storage.biter_health_boost_units) do
        units_to_delete[key] = true
    end

    --Remove valid health boost entries from deletion
    local validtypes = {}
    for k, v in pairs(entity_types) do
        if v then
            table.insert(validtypes, k)
        end
    end
    for _, surface in pairs(game.surfaces) do
        for _, unit in pairs(surface.find_entities_filtered({ type = validtypes })) do
            units_to_delete[unit.unit_number] = nil
        end
    end

    --Remove abandoned health boost entries
    for key, _ in pairs(units_to_delete) do
        storage.biter_health_boost_units[key] = nil
    end
end

local function create_boss_healthbar(entity, size)
    return rendering.draw_sprite(
        {
            sprite = 'virtual-signal/signal-white',
            tint = { 0, 200, 0 },
            x_scale = size * 15,
            y_scale = size,
            render_layer = 'light-effect',
            target = {
                entity = entity,
                offset = { 0, -2.5 },
            },
            surface = entity.surface
        }
    )
end

local function set_boss_healthbar(health, max_health, healthbar_id)
    local m = health / max_health
    local x_scale = healthbar_id.y_scale * 15
    healthbar_id.x_scale = x_scale * m
    healthbar_id.color = { math.floor(255 - 255 * m), math.floor(200 * m), 0 }
end

function Public.add_unit(unit, health_multiplier)
    if not health_multiplier then
        health_multiplier = storage.biter_health_boost
    end
    storage.biter_health_boost_units[unit.unit_number] = {
        math_floor(unit.max_health * health_multiplier),
        math_round(1 / health_multiplier, 5)
    }
    clean_table()
end

function Public.add_boss_unit(unit, health_multiplier, health_bar_size)
    if not health_multiplier then
        health_multiplier = storage.biter_health_boost
    end
    if not health_bar_size then
        health_bar_size = 0.5
    end
    local health = math_floor(unit.max_health * health_multiplier)
    storage.biter_health_boost_units[unit.unit_number] = {
        health,
        math_round(1 / health_multiplier, 5),
        { max_health = health, healthbar_id = create_boss_healthbar(unit, health_bar_size), last_update = game.tick }
    }
    clean_table()
end

local function on_entity_damaged(event)
    local biter = event.entity
    if not (biter and biter.valid) then
        return
    end
    if not entity_types[biter.type] then
        return
    end

    local biter_health_boost_units = storage.biter_health_boost_units

    local unit_number = biter.unit_number

    --Create new health pool
    local health_pool = biter_health_boost_units[unit_number]
    if not health_pool then
        if storage.biter_health_boost_forces[biter.force.index] then
            Public.add_unit(biter, storage.biter_health_boost_forces[biter.force.index])
        else
            Public.add_unit(biter, storage.biter_health_boost)
        end
        health_pool = storage.biter_health_boost_units[unit_number]
    end

    --Process boss unit health bars
    local boss = health_pool[3]
    if boss then
        if boss.last_update + 10 < game.tick then
            set_boss_healthbar(health_pool[1], boss.max_health, boss.healthbar_id)
            boss.last_update = game.tick
        end
    end

    --Reduce health pool
    health_pool[1] = health_pool[1] - event.final_damage_amount

    --Set entity health relative to health pool
    biter.health = health_pool[1] * health_pool[2]

    --Proceed to kill entity if health is 0
    if biter.health > 0 then
        return
    end

    if event.cause then
        if event.cause.valid then
            event.entity.die(event.cause.force, event.cause)
            return
        end
    end
    biter.die(biter.force)
end

local function on_init()
    storage.biter_health_boost = 1
    storage.biter_health_boost_forces = {}
    storage.biter_health_boost_units = {}
    storage.biter_health_boost_count = 0
end

local event = require 'utils.event'
event.on_init(on_init)
event.add(defines.events.on_entity_damaged, on_entity_damaged)

return Public
