local task       = require "lib.utils.task"

--- ===========ЛОГИКА ЭФФЕКТОВ И ЧТО С ЭТИМ ЕДЯТ===========
--- читать здесь: https://docs.google.com/document/d/1Hxa5dOLaeRpLQOs5H-oIDDuLLhKbDw40lR9d62Zb4Tg/edit?usp=sharing

--- behavior thats holds all effects that we applied
--- @class EffectsBehavior : Behavior
--- @field effectsPriority Effect[] хранит эффекты в порядке их применения
--- @field effectsProperties table<Effect, { stacks: integer, intensity: integer }> хранит характеристики эффектов
--- @field effectbook Effect[] все возможные эффекты (хз надо ли так вообще)
local behavior   = {}
behavior.__index = behavior
behavior.id      = "effects"

--- @return EffectsBehavior
function behavior.new()
    local efb = require "lib.effectbook"
    return setmetatable({
        effectbook = efb.of { efb.bleeding },
        effectsPriority = {},
        effectsProperties = {},
    }, behavior)
end

--- проверяет, можно ли наложить эффект и при наложении его применяет
--- @param effect Effect
--- @param stacks integer
function behavior:addEffect(effect, stacks, intensity)
    if effect.beforeBirth then
        local task1 = effect:beforeBirth(self.owner, intensity)
        if task1 then
            task1(function() end)
        end
    end
    -- проверяем эффект на возможности суммирования (aka противоречия)
    for i, ef in ipairs(self.effectsPriority) do
        if ef == effect then
            self.effectsProperties[ef] = {
                stacks = stacks + self.effectsProperties[ef].stacks,
                intensity = intensity
            }
            local task1 = effect:afterBirth(self.owner, intensity)
            if task1 then
                task1(function() end)
            end
            return
        end
        local effectSum = effect:sum(ef)
        if effectSum then
            -- применяем результат суммы и удаляем эффект
            return
        end
    end

    self.effectsPriority[#self.effectsPriority + 1] = effect
    self.effectsProperties[effect] = {
        stacks = stacks,
        intensity = intensity
    }
    print("[Effects]: мы применили эффект!!")
    local task1 = effect:afterBirth(self.owner, intensity)
    if task1 then
        task1(function() end)
    end
end

--- О ДААА ЭТА ФУНКЦИЯ МЕНЯЕТ СОСТОЯНИЕ О ДАААААА О ДАААААААААА
--- @param effect Effect
--- @param amount integer
function behavior:deleteStacks(effect, amount)
    print("[Effects]: удаляем стаки!!")
    self.effectsProperties[effect].stacks = self.effectsProperties[effect].stacks -
        amount -- !!!!!!!!!!!!!!!! <<<<< 21+ only
    if self.effectsProperties[effect].stacks <= 0 then
        print("[Effects]:", effect.tag, "ДОЛЖЕН БЫТЬ СТЁРТ")
        self.effectsProperties[effect] = nil
        for i, ef in ipairs(self.effectsPriority) do
            if ef == effect then
                table.remove(self.effectsPriority, i)
                print("[Effects]:", effect.tag, "СТЁРТ")
            end
        end
    end
end

--- должна вызываться перед смертью персонажа
function behavior:beforeDeath()
    for i, ef in ipairs(self.effectsPriority) do
        local task1 = ef:beforeDeath(self.owner, self.effectsProperties[ef].intensity)
        if task1 then
            task1(function() end)
        end
    end
end

--- должна вызываться после смерти персонажа (может ли такая ситуация возникнуть вообще?)
function behavior:afterDeath()
    for i, ef in ipairs(self.effectsPriority) do
        local task1 = ef:afterDeath(self.owner, self.effectsProperties[ef].intensity)
        if task1 then
            task1(function() end)
        end
    end
end

--- должен вызываться в начале хода
function behavior:beforeTurn()
    for i, ef in ipairs(self.effectsPriority) do
        local task1 = ef:beforeTurn(self.owner, self.effectsProperties[ef].intensity)
        if task1 then
            task1(function() end)
        end
    end
end

--- должен вызываться в конце хода
function behavior:afterTurn()
    for i, ef in pairs(self.effectsPriority) do
        local task1 = ef:afterTurn(self.owner, self.effectsProperties[ef].intensity)
        if task1 then
            task1(function() end)
        end
    end
end

--- должен вызываться перед кастом спелла
function behavior:beforeCast()
    for i, ef in ipairs(self.effectsPriority) do
        local task1 = ef:beforeCast(self.owner, self.effectsProperties[ef].intensity)
        if task1 then
            task1(function() end)
        end
    end
end

--- должен вызываться после каста спелла
function behavior:afterCast()
    for i, ef in pairs(self.effectsPriority) do
        local task1 = ef:afterCast(self.owner, self.effectsProperties[ef].intensity)
        if task1 then
            task1(function() end)
        end
    end
end

return behavior
