local easing = require "lib.utils.easing"
local pf = require "lib.pathfinder"
local utils = require "lib.utils.utils"

--- @alias AIAction fun(self: AIBehavior): Task<nil>

--- @return Character
local function closestCharacter(char)
    local caster = Vec3 {}
    char:try(Tree.behaviors.positioned, function(b)
        caster = b.position
    end)
    local charTarget
    local minDist = 88005553535 -- spooky magic number
    for k, v in pairs(Tree.level.characters) do
        v:try(Tree.behaviors.positioned, function(b)
            local dist = ((caster.x - b.position.x) ^ 2 + (caster.y - b.position.y) ^ 2) ^ 0.5
            if dist < minDist and dist ~= 0 then
                minDist = dist
                charTarget = v
            end
            -- print(k, b.position)
        end)
    end
    return charTarget
end

-- --- Возвращает все точки в радиусе в виде векторов (должен по крайней мере)
-- --- @param radius integer
-- --- @param center Vec3
-- --- @return Vec3[]
-- local function circleVectors(center, radius)
--     local vecs = {}
--     local res = {}
--     for t = 0, 2 * math.pi, EPSILON do
--         local x = math.cos(t) * radius + center.x
--         local y = math.sin(t) * radius + center.y
--         table.insert(vecs, Vec3 { math.floor(x), math.floor(y) })
--     end
--     for _, v in pairs(vecs) do
--         local i = 1
--         while i <= #res and (res[i].x ~= v.x or res[i].y ~= v.y) do
--             i = i + 1
--         end
--         if i == #res + 1 or #res == 0 then
--             table.insert(res, v)
--             print('[AI]: circle vecs:', v)
--         end
--     end
--     return res
-- end

--- Возвращает все точки в радиусе в виде векторов (должен по крайней мере)
--- @param radius integer
--- @param center Vec3
--- @return Vec3[]
local function circleVectors(center, radius)
    local dx, dy, err = radius, 0, 1 - radius
    local vecs, res = {}, {}
    while dx >= dy do
        table.insert(vecs, Vec3 { center.x + dx, center.y + dy })
        table.insert(vecs, Vec3 { center.x - dx, center.y + dy })
        table.insert(vecs, Vec3 { center.x + dx, center.y - dy })
        table.insert(vecs, Vec3 { center.x - dx, center.y - dy })
        table.insert(vecs, Vec3 { center.x + dy, center.y + dx })
        table.insert(vecs, Vec3 { center.x - dy, center.y + dx })
        table.insert(vecs, Vec3 { center.x + dy, center.y - dx })
        table.insert(vecs, Vec3 { center.x - dy, center.y - dx })
        dy = dy + 1
        if err < 0 then
            err = err + 2 * dy + 1
        else
            dx, err = dx - 1, err + 2 * (dy - dx) + 1
        end
    end
    for _, v in pairs(vecs) do
        local i = 1
        while i <= #res and (res[i].x ~= v.x or res[i].y ~= v.y) and v.x >= 0 and v.y >= 0 do
            i = i + 1
        end
        if i == #res + 1 or #res == 0 then
            table.insert(res, v)
            print('[AI]: circle vecs:', v)
        end
    end
    return vecs
end

--- ищет пути к ближайшему персу в определённом радиусе
--- @param owner Character
--- @param radius integer  здесь мы должны сами определять, сколько должны не доходить до персонажа (1 <= n)
--- @return Vec3|nil
local function pathToClosestCharacter(owner, radius)
    local charTarget = closestCharacter(owner)
    local targetPosition, ownerPosition = charTarget:has(Tree.behaviors.positioned), owner:has(Tree.behaviors.positioned)
    if not targetPosition or not ownerPosition then return end

    local circleVecs = circleVectors(targetPosition.position, radius)
    local target = circleVecs[#circleVecs]
    local path = pf(ownerPosition.position, target)
    for i, c in ipairs(circleVecs) do
        local newPath = pf(ownerPosition.position, c)
        if newPath:size() < path:size() then
            path = newPath
            target = c
        end
    end
    return target
end

--- @type table<Class, AIAction>
local aiNature = {
    dev_warrior = function(self)
        return function(callback) -- почему так, описано в Task
            self.owner:try(Tree.behaviors.spellcaster, function(spellB)
                self.target = pathToClosestCharacter(self.owner, 1)
                local attackTarget = closestCharacter(self.owner):has(Tree.behaviors.positioned)
                if not attackTarget then return end
                local task1 = spellB.spellbook[1]:cast(self.owner, self.target)
                if task1 then
                    task1(
                        function()
                            -- здесь мы оказываемся после того, как сходили в первый раз
                            print('[AI]: я походил')
                            local task2 = spellB.spellbook[3]:cast(self.owner, attackTarget.position)
                            if task2 then
                                -- дергаем функцию после завершения хода
                                print('[AI]: и ударил')
                                task2(callback)
                            else
                                print('[AI]: чёт не бьётся')
                                callback()
                            end
                        end
                    )
                else
                    print('рот этого казино')
                    callback()
                end
            end)
        end
    end,
    dev_mage = function(self)
        return function(callback)
            print("etoh... bleh")
            callback()
        end
    end
}



--- @class AIBehavior : Behavior
--- @field target Vec3?
local behavior = {}
behavior.__index = behavior
behavior.id = "ai"

--- @param class Class
function behavior.new(class)
    return setmetatable({
        makeTurn = aiNature[class]
    }, behavior)
end

return behavior
