local math_utils = require("luxmotion.utils.math")

local M = {}

-- Optimized animation system with persistent timer and frame pooling
local animation_timer = nil
local frame_queue = {}
local is_running = false

-- Animation object pool for memory efficiency
local animation_pool = {}
local pool_size = 0
local MAX_POOL_SIZE = 10

local function get_pooled_animation()
  if pool_size > 0 then
    pool_size = pool_size - 1
    return table.remove(animation_pool)
  else
    return {
      start_time = 0,
      duration_ns = 0,
      easing_fn = nil,
      update_fn = nil,
      complete_fn = nil,
      completed = false
    }
  end
end

local function return_to_pool(animation)
  if pool_size < MAX_POOL_SIZE then
    animation.completed = false
    animation.start_time = 0
    animation.duration_ns = 0
    animation.easing_fn = nil
    animation.update_fn = nil
    animation.complete_fn = nil
    pool_size = pool_size + 1
    table.insert(animation_pool, animation)
  end
end

local function process_frame_queue()
  local current_time = vim.loop.hrtime()
  
  for i = #frame_queue, 1, -1 do
    local animation = frame_queue[i]
    if not animation.completed then
      local elapsed = current_time - animation.start_time
      local progress = math.min(elapsed / animation.duration_ns, 1.0)
      
      local eased_progress = animation.easing_fn(progress)
      animation.update_fn(eased_progress, progress)
      
      if progress >= 1.0 then
        animation.completed = true
        animation.complete_fn()
        table.remove(frame_queue, i)
        return_to_pool(animation)
      end
    else
      table.remove(frame_queue, i)
      return_to_pool(animation)
    end
  end
  
  -- Stop timer if no animations are running
  if #frame_queue == 0 then
    if animation_timer then
      animation_timer:stop()
    end
    is_running = false
  end
end

function M.create_loop(start_time, duration_ns, easing_fn, update_fn, complete_fn)
  local animation = get_pooled_animation()
  animation.start_time = start_time
  animation.duration_ns = duration_ns
  animation.easing_fn = easing_fn
  animation.update_fn = update_fn
  animation.complete_fn = complete_fn
  animation.completed = false
  
  table.insert(frame_queue, animation)
  
  -- Start persistent timer if not already running
  if not is_running then
    if not animation_timer then
      animation_timer = vim.loop.new_timer()
    end
    
    animation_timer:start(16, 16, process_frame_queue)
    is_running = true
  end
  
  -- Return immediate function for compatibility
  return function() end
end

function M.interpolate_values(start_val, end_val, eased_progress)
  return math.floor(math_utils.lerp(start_val, end_val, eased_progress) + 0.5)
end

function M.calculate_duration(base_duration, distance_factor)
  return math.floor(base_duration * distance_factor)
end

function M.get_current_time()
  return vim.loop.hrtime()
end

function M.duration_to_nanoseconds(duration_ms)
  return duration_ms * 1000000
end

return M