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

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

-- INIT functions
-- Initialize the player

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

  self.startx, self.starty = x, y
  self:setSpawnPoint(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:initStats(TEMP_PLAYERID)
  self:initWeapon()
  self:initHUD()

  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 = playerID
  self.stats = game.pigmanager:getPig(1)
  self.playerID = playerID
end

function Player:initStats(playerID)
  self:getStats(playerID)
  self:resetLife()

  self.itemList = {}
  self.score = 0
  self.gold  = 0

  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:update(dt)
  if (self.isAlive) then
    Player.super.update(self, dt)
  else
    -- Only update timers if the player is dead
    self:updateTimers(dt)
  end
end

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:timerResponse(timer)
  if (timer == "respawn") then
    self:respawn()
  end
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(self)
  end
end

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

  if (math.abs(self.ysp) >= self.maxysp) then
    self.ysp = self.maxysp * utils.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), 0, self)
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:draw()
  if (self.isAlive) then
    Player.super.draw(self)
  end
end

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

-- HUD FUNCTIONS
-- All functions related to the HUD

function Player:initHUD()
  local mediumfont, smallfont
  mediumfont  = self.scene.assets.fonts["medium"]
  smallfont   = self.scene.assets.fonts["small"]
  self.hpbar = game.gui.newProgressBar("greenbar",  mediumfont, smallfont, "HP", 96)
  self.mpbar = game.gui.newProgressBar("bluebar",   mediumfont, smallfont, "MP", 96)

  self.itembox = game.gui.newTextBox("assets/sprites/gui/textbox/yellowbox.png", 24,24)
end

function Player:drawHUD()
  utils.graphics.resetColor()
  local hp = 0
  local mp = 0
  local weapon = 0
  love.graphics.draw(self.itembox, 16, 16)

  if (self.isAlive) then
    hp = self.hp / self.stats.maxHP
    mp = self.mp / self.stats.maxMP
    weapon = self.weapon
  end

  if (weapon ~= 0) and (weapon ~= nil) then
    self.scene.assets.tileset["weapon"]:drawTile(weapon,28,28,0,1,1,8,8)
  end

  self.hpbar:draw(68, 14, hp)
  self.mpbar:draw(68, 30, mp)

  self.scene.assets.fonts["medium"]:set()

  love.graphics.printf( utils.math.numberToString(self.score, 6), 373, 10, 96, "right")
  love.graphics.printf( utils.math.numberToString(self.gold, 4), 373, 25, 96-18, "right")
  love.graphics.setColor(1, 1, 85/256)
  love.graphics.printf( "G", 373, 25, 96, "right")
  utils.graphics.resetColor()
end

function Player:addScore(score)
  self.score = self.score + score
end

function Player:addGold(gold)
  self.gold = self.gold + gold
end

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

function Player:setSpawnPoint(x, y)
  self.spawn    = {}
  self.spawn.x  = x
  self.spawn.y  = y
end

function Player:goToSpawnPoint( )
  self.x = self.spawn.x
  self.y = self.spawn.y
  self.world:changeActorData(self)
end

function Player:respawn()
  self.isAlive = true
  self:goToSpawnPoint( )
end

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

  self.isAlive = true
end

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

function Player:die()
  self:addTimer("respawn", 1)
  self.isAlive = false
end


return Player
