local Entity = require "scenes.levels.entities.parent"

local Player = Entity:extend()

-- INIT functions
-- Initialize the player

function Player:new(level, x, y, playerID)

  local w, h = 32, 24
  self.direction = 1

  self.startx, self.starty = x, y

  Player.super.new(self, level, "player", x - (w / 2), y - (h / 2), w, h)
  self.manager = level.playermanager

  self.center = {
    x = self.x,
    y = self.y,
  }

  self.stats = {}
  self:getStats(playerID)
  self:lifeInit()
  self:initWeapon()

  self.currentWeapon = 1

  self:initMovement()

  self:setDebugColor(0,255,0)
end

function Player:getStats(playerID)
  self.pigID = self.manager.players[playerID].pigID
  self.stats = game.pigmanager:getPig(1)
  self.playerID = playerID
end

function Player:lifeInit()
  self.hp = self.stats.maxHP
  self.mp = self.stats.maxMP
end

function Player:initMovement()
  self.maxxsp   = 16*60
  self.maxysp   = self.maxxsp
  self.topsp    = 4.5*60
  self.acc      = 0.046875*60*1.5
  self.dec      = 0.5*60
  self.frc      = self.acc
  self.grav     = 1
  self.jmp      = -5*60

  self.isJumping = false
end

function Player:initWeapon()
  self.weaponID = 1
  self:setWeapon()
end

-- UPDATE and COLLISION functions
-- Physics and function called every game update

function Player:update(dt)
  self.keys = self.level.keys
  self.level.assets.sprites[self.stats.race]:setCustomSpeed(math.abs(self.xsp / 60))
  self:actionMove(dt)

  self:shoot(dt)

  self:gravity(dt)
  self:limitMovement()
  self:setFilter()
  local cols, cols_len = self:move(dt)

  self:resolveCollisions(cols, cols_len)

  self.center.x, self.center.y = self:getCenter()

  self:getDirection()

  local _, height = self.world:getDimensions()

  if self.y >= (height + 64) then
    self:die()
  end
end

function Player:setFilter()
  self.filter = function(item, other)
    if      (other.collType == "wall")  then return 'slide'
    elseif  (other.collType == "block")    then return 'slide'
    elseif  (other.collType == "platform") and
            (self.ysp > 0) and
            ((self.y+24) <= other.y)    then return 'slide'
    elseif  (other.collType == "loot")    then return 'cross'
    else    return nil
    end
  end
end

function Player:resolveCollisions(cols, cols_len)
  local cols, cols_len = cols, cols_len
  for j=1,cols_len do
    local other = cols[j].other
    if (other.collType == "loot") then
      other:takeLoot()
    end
  end
end

function Player:limitMovement()
  if (math.abs(self.xsp) >= self.maxxsp) then
    self.xsp = self.maxxsp * math.sign(self.xsp)
  end

  if (math.abs(self.ysp) >= self.maxysp) then
    self.ysp = self.maxysp * math.sign(self.ysp)
  end
end

-- GAMEPLAY functions
-- Where the player act and move

function Player:shoot()
  if self.keys["B"].isPressed then
    self:launchWeapon()
  end
  if self.keys["C"].isPressed then
    self:changeWeapon(self.weaponID+1)
  end
end

function Player:actionMove(dt)
  local dx, dy = 0, 0

  if self.keys["right"].isDown and not (self.keys["left"].isDown) then
    if (self.xsp < self.topsp) then
      if (self.xsp < 0) then
        self.xsp = self.xsp + self.dec
      else
        self.xsp = self.xsp + self.acc
      end
    end
  elseif self.keys["left"].isDown and not (self.keys["right"].isDown) then
    if (self.xsp > -self.topsp) then
      if (self.xsp > 0) then
        self.xsp = self.xsp - self.dec
      else
        self.xsp = self.xsp - self.acc
      end
    end
  else
    self:friction(dt)
  end

  if (self.grav == 0) then
    if self.keys["down"].isPressed and (self.y < 1000) then
      self.ysp =  160
    elseif self.keys["up"].isPressed and (self.y > 0) then
      self.ysp = -160
    end
  end

  if (self.onGround == true) then
    self.isJumping = false
  end

  multijump = true

  if ((self.onGround == true) or multijump) and self.keys["A"].isPressed then
    self.ysp = self.jmp
    self.isJumping = true
    self.level.assets:playSFX("jump")
  end

  if (self.isJumping == true) and (self.ysp < (-4 * 60)) and (not (self.keys["A"].isDown)) then
    self.ysp = -4 * 60
  end

  return dx, dy
end

function Player:launchWeapon()
  self.obj.Weapon(self.level, self.center.x, self.center.y, self.weapon, 350 * utils.math.sign(self.direction))
end

function Player:changeWeapon(id)
  local maxWeapon = #self.stats.weaponList
  self.weaponID = utils.math.wrap(id, 1, maxWeapon)
  self:setWeapon()
end

function Player:setWeapon()
  self.weapon = self.stats.weaponList[self.weaponID]
end

-- DRAW functions

function Player:getAnimation()
local animation = "idle"

  if (self.onGround) then
    if (self.xsp == 0) then
      animation = "idle"
    else
      if  (self.keys["left"].isDown  and (self.xsp > 0)) or
          (self.keys["right"].isDown and (self.xsp < 0)) then
        animation = "brake"
      else
        animation = "walk"
      end
    end
  else
    if (self.ysp < 0) and (self.isJumping) then
      animation = "jump"
    else
      animation = "fall"
    end
  end

  if not (self.level.assets.sprites[self.stats.race]:animationExist(animation)) then
    animation = "idle"
  end

  self.level.assets.sprites[self.stats.race]:changeAnimation(animation, false)

  return animation
end

function Player:draw(dt)
  local drawx, drawy = utils.math.floorCoord(self.center.x, self.center.y)
  local animation = self:getAnimation()
  self.level.assets.sprites[self.stats.race]:drawAnimation(drawx, drawy, 0, self.direction, 1, 16, 36)
end

-- DEATH and HIT functions
-- All function related to damage management

function Player:takeHit(damage)
  if (self.hp <= damage) then
    self:die()
  else
    self.hp = self.hp - damage
  end
end

function Player:die()
  self.manager:setDeathTimer(1)
  self:destroy()
end


return Player
