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

local Player = Entity:extend()
local PLAYER_W, PLAYER_H = 32, 24

-- INIT functions
-- Initialize the player

function Player:new(world, x, y, playerID)
  self.direction = 1

  self.startx, self.starty = x, y

  Player.super.new(self, world, "player", x, y, PLAYER_W, PLAYER_H)

  self.manager = self.scene.playermanager

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

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

  self.currentWeapon = 1

  self:setDebugColor(0,255,0)
  self:setSprite(self.stats.race, PLAYER_W/2, -PLAYER_H/2)
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:initStats()
  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.xfrc     = self.acc*60*4
  self.jmp      = -5*60

  self:setGravityFlag(true)

  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:updateStart(dt)
  self.keys = self.scene.sources[1].keys

  -- Gameplay movement functions
  self:actionMove(dt)
  self:shoot(dt)

  self:limitMovement()
end

function Player:updateEnd(dt)
  self.center.x, self.center.y = self:getCenter()

  local _, height = self.world:getDimensions()
  if self.y >= (height + 64) then
    self:die()
  end

  -- Cosmetic changes are grouped at the end of the step
  -- to be sure they reflect as good as possible the actual situation
  self:getDirection()
  self:setCustomSpeed(math.abs(self.xsp / 60))
  self:setAnimation()
end

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

function Player:collisionResponse(collision)
  local other = collision.other

  if (other.type == "loot") then
    other:takeLoot()
  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:applyFriction(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.scene.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.world, 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:setAnimation()
local animation = "idle"
self:setSpriteScallingX(self.direction)


  if (self.onGround) then
    if (self.xsp == 0) then
      self:changeAnimation("idle", false)
    else
      if  (self.keys["left"].isDown  and (self.xsp > 0)) or
          (self.keys["right"].isDown and (self.xsp < 0)) then
        self:changeAnimation("brake", true)
      else
        self:changeAnimation("walk", false)
      end
    end
  else
    if (self.ysp < 0) and (self.isJumping) then
      self:changeAnimation("jump", true)
    else
      self:changeAnimation("fall", true)
    end
  end
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
