local utils = require "lib.utils.utils"

--- @class Effect
--- @field tag string
local effect = {}
effect.__index = effect

--- Предполагается, что в каждую функцию будет передаваться `Character` и параметр `intensity`, который отвечает за силу спелла
--- @alias EffectFunc fun(owner: Character, intensity: integer): Task<nil>|nil
--- @alias EffectDamageFunc fun(owner: Character, intensity: integer, damage: integer): Task<nil>|nil
--- @alias EffectRegenFunc fun(owner: Character, intensity: integer, amountHp: integer): Task<nil>|nil
--- @alias EffectData { tag: string, [string]: EffectFunc|EffectDamageFunc|EffectRegenFunc }

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:beforeBirth(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterBirth(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:beforeDeath(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterDeath(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:beforeTurn(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterTurn(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:beforeCast(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterCast(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @param damage integer
--- @return Task<nil>|nil
function effect:beforeAttack(owner, intensity, damage) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterAttack(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @param damage integer
--- @return Task<nil>|nil
function effect:beforeDamage(owner, intensity, damage) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterDamage(owner, intensity) end

--- @param owner Character
--- @param intensity integer
--- @param amountHp integer кол-во хп для регена
--- @return Task<nil>|nil
function effect:beforeRegeneration(owner, intensity, amountHp) end

--- @param owner Character
--- @param intensity integer
--- @return Task<nil>|nil
function effect:afterRegeneration(owner, intensity) end

--- @param other Effect
--- @return Effect|nil
function effect:sum(other) end

function effect:update(dt) end

function effect:draw() end

--- дип сравнение эффектов
--- @param other Effect
--- @return boolean
function effect:__eq(other)
    return utils.deepComprasion(self, other)
end

--- @todo переделать дату и прочее
-- --- @param data {tag: string, beforeBirth: fun(owner: Character)?, beforeDeath: fun(owner: Character)?, beforeTurn: (fun(owner: Character): Task<nil>|nil), afterTurn: (fun(owner: Character): Task<nil>|nil), sum: fun(owner: Character)?}
--- @param data EffectData
--- @return Effect
local function new(data)
    local newEffect = setmetatable({
        tag = data.tag
    }, effect)

    function newEffect:beforeBirth(owner, intensity)
        if not data.beforeBirth then return end
        return data.beforeBirth(owner, intensity)
    end

    function newEffect:afterBirth(owner, intensity)
        if not data.afterBirth then return end
        return data.afterBirth(owner, intensity)
    end

    function newEffect:beforeDeath(owner, intensity)
        if not data.beforeDeath then return end
        return data.beforeDeath(owner, intensity)
    end

    function newEffect:afterDeath(owner, intensity)
        if not data.afterDeath then return end
        return data.afterDeath(owner, intensity)
    end

    function newEffect:beforeTurn(owner, intensity)
        if not data.beforeTurn then return end
        return data.beforeTurn(owner, intensity)
    end

    function newEffect:afterTurn(owner, intensity)
        if not data.afterTurn then return end
        return data.afterTurn(owner, intensity)
    end

    function newEffect:beforeCast(owner, intensity)
        if not data.beforeCast then return end
        return data.beforeCast(owner, intensity)
    end

    function newEffect:afterCast(owner, intensity)
        if not data.afterCast then return end
        return data.afterCast(owner, intensity)
    end

    function newEffect:beforeAttack(owner, intensity, damage)
        if not data.beforeAttack then return end
        return data.beforeAttack(owner, intensity, damage)
    end

    function newEffect:afterAttack(owner, intensity)
        if not data.afterAttack then return end
        return data.afterAttack(owner, intensity)
    end

    function newEffect:beforeDamage(owner, intensity, damage)
        if not data.beforeDamage then return end
        return data.beforeDamage(owner, intensity, damage)
    end

    function newEffect:afterDamage(owner, intensity)
        if not data.afterDamage then return end
        return data.afterDamage(owner, intensity)
    end

    function newEffect:beforeRegeneration(owner, intensity, amountHp)
        if not data.beforeRegeneration then return end
        return data.beforeRegeneration(owner, intensity, amountHp)
    end

    function newEffect:afterRegeneration(owner, intensity)
        if not data.afterRegeneration then return end
        return data.afterRegeneration(owner, intensity)
    end

    --- дип сравнение эффектов
    --- @param other Effect
    --- @return boolean
    function newEffect:__eq(other)
        return utils.deepComparison(self, other)
    end

    return newEffect
end

return { new = new }
