local utils = require "lib.utils.utils"

--- Отвечает за размещение и перемещение по локации
--- @class MapBehavior : Behavior
--- @field position Vec3
--- @field runTarget Vec3 точка, в которую в данный момент бежит персонаж
--- @field displayedPosition Vec3 точка, в которой персонаж отображается
--- @field t0 number время начала движения для анимациии
--- @field path Deque путь, по которому сейчас бежит персонаж
--- @field animationNode? AnimationNode AnimationNode, с которым связана анимация перемещения
--- @field size Vec3
local mapBehavior = {}
mapBehavior.__index = mapBehavior
mapBehavior.id = "map"


--- @param position? Vec3
--- @param size? Vec3
function mapBehavior.new(position, size)
    return setmetatable({
        position = position or Vec3({}),
        displayedPosition = position or Vec3({}),
        size = size or Vec3({ 1, 1 }),
    }, mapBehavior)
end

--- @param position Vec3
function mapBehavior:lookAt(position)
    self.owner:try(Tree.behaviors.sprite,
        function(sprite)
            if position.x > self.displayedPosition.x then sprite.side = sprite.RIGHT end
            -- (sic!)
            if position.x < self.displayedPosition.x then sprite.side = sprite.LEFT end
        end
    )
end

--- @param path Deque
--- @param animationNode AnimationNode
function mapBehavior:followPath(path, animationNode)
    if path:is_empty() then return animationNode:finish() end
    self.animationNode = animationNode
    self.position = self.displayedPosition
    self.owner:try(Tree.behaviors.sprite, function(sprite)
        sprite:loop("run")
    end)
    self.path = path;
    ---@type Vec3
    local nextCell = path:peek_front()
    self:runTo(nextCell)
    path:pop_front()
end

--- @param target Vec3
function mapBehavior:runTo(target)
    self.t0 = love.timer.getTime()
    self.runTarget = target
    self.owner:try(Tree.behaviors.sprite,
        function(sprite)
            if target.x < self.position.x then
                sprite.side = Tree.behaviors.sprite.LEFT
            elseif target.x > self.position.x then
                sprite.side = Tree.behaviors.sprite.RIGHT
            end
        end
    )
end

function mapBehavior:update(dt)
    if self.runTarget then
        local delta = love.timer.getTime() - self.t0 or love.timer.getTime()
        local fraction = delta /
            (0.5 * self.runTarget:subtract(self.position):length()) -- бежим одну клетку за 500 мс, по диагонали больше
        if fraction >= 1 then                                       -- анимация перемещена завершена
            self.position = self.runTarget
            if not self.path:is_empty() then                        -- еще есть, куда бежать
                self:runTo(self.path:pop_front())
            else                                                    -- мы добежали до финальной цели
                self.owner:try(Tree.behaviors.sprite, function(sprite)
                    sprite:loop("idle")
                end)
                self.runTarget = nil
                if self.animationNode then self.animationNode:finish() end
            end
        else                                                                             -- анимация перемещения не завершена
            self.displayedPosition = utils.lerp(self.position, self.runTarget, fraction) -- линейный интерполятор
        end
    end
end

return mapBehavior
