local format = string.format

local reap = require("lib.reap")

local BASE = reap.base_path(...)
local component_builder = require(format("%s.component", BASE))
local entity_builder = require(format("%s.entity", BASE))

local Concord = require("lib.Concord")

-- Modules
local Entity     = Concord.entity
local Component  = Concord.component
local System     = Concord.system
local World      = Concord.world

local main_wrapper = require "love_src.wrapper.lappy.world"
---@class wrappers.Concord.world : lappy.world
local wrapper = main_wrapper:extend()

function wrapper:new(path, name)
  wrapper.super.new(self, path, name)
  self.is_loaded = false
  self.world = World()
  self.entities = {}
end

local function load_systems(world, system_paths)
  for _, p in pairs(system_paths) do
    local Systems = {}
    Concord.utils.loadNamespace(p, Systems)
    for k, s in pairs(Systems) do
      for c, l in pairs(s.components) do
        if (type(c) == "number") then
          component_builder.state(l)
        else
          component_builder.component(c, l)
        end
      end
      local new_s = s.new()
      if (new_s) then
        world:addSystem(
          new_s
        )
      end
    end
  end
end

local function load_entities(self, world, data)
  for _, d in pairs(data) do
    local entity = entity_builder.new()
    entity:assemble(d.assemblage, d.data)
    world:addEntity(entity)
    table.insert(self.entities, entity)
  end
end

function wrapper:load(system_paths, entities_data)
  load_systems(self.world, system_paths)
  load_entities(self, self.world, entities_data)
  self.is_loaded = true
  self.world:emit("load")
end

function wrapper:reload(system_paths, entities_data)
  if not self.is_loaded then
    self:load(system_paths, entities_data)
  end
  self.world:emit("reload")
end

function wrapper:draw()
  self.world:emit("draw")
end

function wrapper:update(dt)
  self.world:emit("update", dt)
end

-- mouse

function wrapper:mousemoved( x, y, dx, dy, istouch)
  self.world:emit("mousemoved", x, y, dx, dy, istouch)
end

function wrapper:mousepressed(x, y, button, istouch, presses)
  self.world:emit("mousepressed", x, y, button, istouch, presses)
end

function wrapper:mousereleased(x, y, button, istouch, presses)
  self.world:emit("mousereleased", x, y, button, istouch, presses)
end

function wrapper:wheelmoved(x, y)
  self.world:emit("wheelmoved", x, y)
end

-- keyboard

function wrapper:keypressed(key, scancode, isrepeat)
  self.world:emit("keypressed", key, scancode, isrepeat)
end

function wrapper:keyreleased(key, scancode)
  self.world:emit("keyreleased", key, scancode)
end

-- touchscreen

function wrapper:touchpressed(id, x, y, dx, dy, pressure)
  self.world:emit("touchpressed", id, x, y, dx, dy, pressure)
end

function wrapper:textinput(t)
  self.world:emit("textinput", t)
end

function wrapper:resize(w,h)
  self.world:emit("rezise", w, h)
end

function wrapper:focus(f)
  self.world:emit("focus", f)
end

function wrapper:quit()
  self.world:emit("quit")
end

-- for gamepad support also add the following:

function wrapper:joystickadded(joystick)
  self.world:emit("joystickadded", joystick)
end

function wrapper:joystickremoved(joystick)
  self.world:emit("joystickremoved", joystick)
end

function wrapper:gamepadpressed(joystick, button)
  self.world:emit("gamepadpressed", joystick, button)
end

function wrapper:gamepadreleased(joystick, button)
  self.world:emit("gamepadreleased", joystick, button)
end

function wrapper:gamepadaxis(joystick, axis, value)
  self.world:emit("gamepadaxis", joystick, axis, value)
end

return wrapper
