#include "StationContent.h"

#include <QVBoxLayout>

#include "BarRow.h"
#include "EntityAdmin.h"
#include "FactionComponent.h"
#include "HealthComponent.h"
#include "ModuleOwnerComponent.h"
#include "Simulation.h"
#include "StatRow.h"
#include "WeaponComponent.h"

StationContent::StationContent(const SelectionContext& context,
                               const SelectionRequest& request, QWidget* parent)
    : SelectionContent(context, std::nullopt, parent)
    , m_entity(request.actors.front())
{
    m_hpBar       = new BarRow(tr("HP"), this);
    m_damageRow   = new StatRow(tr("Damage"), this);
    m_rangeRow    = new StatRow(tr("Range"), this);
    m_fireRateRow = new StatRow(tr("Fire rate"), this);

    getRuntimeLayout()->addWidget(m_hpBar);
    getRuntimeLayout()->addWidget(m_damageRow);
    getRuntimeLayout()->addWidget(m_rangeRow);
    getRuntimeLayout()->addWidget(m_fireRateRow);

    EntityAdmin& admin = context.sim->getAdmin();
    const bool isEnemy = admin.isValid(m_entity)
        && admin.hasAll<FactionComponent>(m_entity)
        && admin.get<FactionComponent>(m_entity).isEnemy;
    setIdentity(QPixmap(), isEnemy ? tr("Enemy Defence Station")
                                   : tr("Player Defence Station"));
}

void StationContent::refreshRuntime()
{
    EntityAdmin& admin = getContext().sim->getAdmin();
    if (!admin.isValid(m_entity) || !admin.hasAll<HealthComponent>(m_entity))
    {
        return;
    }
    const HealthComponent& health = admin.get<HealthComponent>(m_entity);

    const double hpFraction = (health.maxHp > 0.0f)
        ? static_cast<double>(health.hp) / health.maxHp
        : 0.0;
    m_hpBar->setValue(hpFraction, tr("%1 / %2")
        .arg(static_cast<int>(health.hp + 0.5f))
        .arg(static_cast<int>(health.maxHp + 0.5f)));

    // A station's weapons are child module entities pointing back at it, so its damage,
    // range and fire rate are read off those rather than off the station itself.
    float totalDamage   = 0.0f;
    float maxRange      = 0.0f;
    float maxFireRateHz = 0.0f;
    bool  hasWeapon     = false;
    const entt::entity station = m_entity;
    admin.forEach<ModuleOwnerComponent, WeaponComponent>(
        [&](entt::entity /*child*/, const ModuleOwnerComponent& owner,
            const WeaponComponent& weapon)
        {
            if (owner.owner != station) { return; }
            hasWeapon = true;
            totalDamage += weapon.damage;
            if (weapon.range_tiles > maxRange)      { maxRange = weapon.range_tiles; }
            if (weapon.fireRateHz  > maxFireRateHz) { maxFireRateHz = weapon.fireRateHz; }
        });

    m_damageRow->setVisible(hasWeapon);
    m_rangeRow->setVisible(hasWeapon);
    m_fireRateRow->setVisible(hasWeapon);
    if (hasWeapon)
    {
        m_damageRow->setValue(
            QString::number(static_cast<double>(totalDamage), 'f', 1));
        m_rangeRow->setValue(tr("%1 tiles")
            .arg(QString::number(static_cast<double>(maxRange), 'f', 1)));
        m_fireRateRow->setValue(tr("%1 /s")
            .arg(QString::number(static_cast<double>(maxFireRateHz), 'f', 1)));
    }
}
