/*Copyright (C) 2010-2023 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "PlayerInfo.hpp"
#include "Player/Player.hpp"
#include "Graphics/Resources/Font.hpp"
#include "Engines/Resources/TextureManager.hpp"

#include "PlayerIcon.hpp"
#include "Tools/ScaledPixel.hpp"
#include "Tools/Format.hpp"
#include <cmath>

namespace
{
    constexpr float BASE_ICON_SCALE = .4f;
    constexpr float WEAPON_ICON_SCALE = .15f;
}

PlayerInfo::PlayerInfo(const Player &player, TextureManager &textureManager,
                       Font &nameFont, Font &weaponsFont, Font &barsFont,
                       float viewWidth) :
Drawable(), m_player(&player),
m_icon(PlayerIcon::load(player.getName(), textureManager)),
m_results(ScaledPixel{viewWidth}(60.f),
          ScaledPixel{viewWidth}(16.f),
          ScaledPixel{viewWidth}(2.f)),
m_barsHeight(static_cast<float>(barsFont.getCharSize()) / 1.3f +
             ScaledPixel{viewWidth}(12.f)),
m_barsWidth(m_barsHeight * 6.f), m_viewWidth(viewWidth)
{
    m_name.setText(player.getName());
    m_name.setFont(nameFont);
    m_name.setColor(Color(255, 255 , 255), Color(0, 0, 0));

    m_shurikenText.setFont(weaponsFont);
    m_shurikenText.setColor(Color(255, 255, 255), Color(0, 0, 0));

    m_lifeText.setFont(barsFont);

    m_shurikenIcon.setTexture(
        textureManager.getTexture("gfx/weapons/shuriken.png"));
    m_shurikenIcon.setScale(
        ScaledPixel{m_viewWidth}.lower(WEAPON_ICON_SCALE, 1.f));

    setIconScale(1.f);
    updateWeaponsText();
    initPositions();
}

void PlayerInfo::draw()
{
    //Update matrix
    Drawable::pushMatrix();
    Drawable::updateMatrix();

    m_icon.draw();
    m_name.draw();

    m_lifeBarBack.draw();
    m_lifeBar.draw();
    m_lifeText.draw();

    m_shurikenIcon.draw();
    m_shurikenText.draw();

    m_results.draw();

    Drawable::popMatrix();
}

void PlayerInfo::update()
{
    //Health
    const int playerHealth = static_cast<int>(ceilf(m_player->getHealth()));

    if (playerHealth != m_knownState.health)
    {
        m_lifeText.setText(Format::format("{} / 100", playerHealth));
        m_lifeBar.setXScale(m_player->getHealth() / 100.f);

        m_knownState.health = playerHealth;
    }

    //Weapons
    updateWeaponsText();
}

void PlayerInfo::initPositions()
{
    const Font &nameFont = (*m_name.getFont());
    const ScaledPixel sp(m_viewWidth);

    const float xBase = m_icon.getXPosition() +
        m_icon.getWidth() * m_icon.getXScale() + sp(10.f);

    //Health bar
    m_lifeBarBack = Polygon::rectangle(m_barsWidth, m_barsHeight,
                                       Color(175, 175, 175, 175));
    m_lifeBarBack.setBorderSize(0.f);

    m_lifeBar = Polygon::rectangle(m_barsWidth, m_barsHeight,
                                   Color(0, 192, 0));
    m_lifeBar.setPosition(xBase,
        static_cast<float>(nameFont.getCharSize()) / 1.3f + sp(8.f));
    m_lifeBar.setBorderSize(0.f);

    m_lifeText.setPosition(m_lifeBar.getXPosition() + sp(20.f),
                           m_lifeBar.getYPosition() + sp(5.f));
    m_lifeText.setColor(Color(255, 255, 255, 200));

    //Weapon icon & text
    const float shurikenWidth =
        m_shurikenIcon.getWidth() * m_shurikenIcon.getXScale();
    const float shurikenHeight =
        m_shurikenIcon.getHeight() * m_shurikenIcon.getYScale();

    m_shurikenIcon.setPosition(xBase,
        m_lifeBar.getYPosition() + m_barsHeight + sp(5.f));
    m_shurikenText.setPosition(xBase + shurikenWidth + sp(4.f),
        m_shurikenIcon.getYPosition() +
        (shurikenHeight - m_shurikenText.getHeight()) / 2.f );

    //Height alignment
    const float itemsHeight = m_shurikenIcon.getYPosition() + shurikenHeight;
    const float diffY =
        (m_icon.getHeight() * m_icon.getYScale() - itemsHeight) / 2.f;

    m_name.setPosition(xBase, diffY);

    m_lifeBar.setYPosition(m_lifeBar.getYPosition() + diffY);
    m_lifeBarBack.setPosition(m_lifeBar.getXPosition(),
                              m_lifeBar.getYPosition());
    m_lifeText.setYPosition(m_lifeText.getYPosition() + diffY);

    m_shurikenIcon.setYPosition(m_shurikenIcon.getYPosition() + diffY);
    m_shurikenText.setYPosition(m_shurikenText.getYPosition() + diffY);

    m_results.setPosition(m_shurikenText.getXPosition() + sp(18.f),
                          m_shurikenText.getYPosition() - sp(3.f));
}

void PlayerInfo::updateWeaponsText()
{
    const unsigned int shurikenAmount =
        m_player->getWeaponsRemaining(WeaponType::Shuriken);

    if (shurikenAmount != m_knownState.shurikenAmount)
    {
        m_shurikenText.setText(std::to_string(shurikenAmount));
        m_knownState.shurikenAmount = shurikenAmount;
    }
}

void PlayerInfo::replaceName(const Utf8::utf8_string &playerName)
{
    m_name.setText(playerName);
    initPositions();
}

void PlayerInfo::setResults(std::uint8_t roundsToWin, std::uint8_t wonRounds)
{
    m_results.reset(roundsToWin, wonRounds);
}

void PlayerInfo::setIconScale(float scale)
{
    m_icon.setScale(ScaledPixel{m_viewWidth}.lower(BASE_ICON_SCALE * scale,
                                                   1.f));
    initPositions();
}

float PlayerInfo::getWidth() const
{
    if (m_barsWidth > m_name.getWidth())
        return m_lifeBar.getXPosition() + m_barsWidth;

    return m_name.getXPosition() + m_name.getWidth();
}

float PlayerInfo::getHeight() const
{
    return m_lifeBar.getYPosition() + m_barsHeight;
}
