#include "FieldMultiContent.h"

#include <map>
#include <string>

#include <QVBoxLayout>

#include "CountRow.h"
#include "DebrisScrap.h"
#include "DisplayName.h"
#include "EntityAdmin.h"
#include "FactionComponent.h"
#include "IconCaption.h"
#include "ItemIconCache.h"
#include "ItemTooltip.h"
#include "ShipIdentityComponent.h"
#include "Simulation.h"
#include "StatRow.h"
#include "StationBodyComponent.h"

FieldMultiContent::FieldMultiContent(const SelectionContext& context,
                                     const SelectionRequest& request, QWidget* parent)
    : SelectionContent(context, std::nullopt, parent)
    , m_debris(request.debris)
    , m_scrapRow(nullptr)
    , m_scrapIcon(context.itemIcons->getInlineIcon(kScrapItemId, font()))
{
    setIdentity(QPixmap(), tr("Mixed selection"));
    setCountSlot(static_cast<int>(request.actors.size() + request.debris.size()));

    buildSummary(request.actors);
}

void FieldMultiContent::buildSummary(const std::vector<entt::entity>& actors)
{
    EntityAdmin& admin = getContext().sim->getAdmin();

    // Grouped by faction, kind and ship schematic, in the order the groups are first
    // seen (REQ-UI-FIELD-MULTI-SELECTION).
    std::vector<QString> keys;
    std::map<QString, int>     counts;
    std::map<QString, QString> labels;

    for (entt::entity actor : actors)
    {
        if (!admin.isValid(actor)) { continue; }
        const bool isEnemy = admin.hasAll<FactionComponent>(actor)
            && admin.get<FactionComponent>(actor).isEnemy;

        QString key;
        QString label;
        if (admin.hasAll<ShipIdentityComponent>(actor))
        {
            const std::string& id = admin.get<ShipIdentityComponent>(actor).schematicId;
            const QString name = QString::fromStdString(toDisplayName(id));
            key = (isEnemy ? QStringLiteral("ship:enemy:")
                           : QStringLiteral("ship:player:"))
                + QString::fromStdString(id);
            label = isEnemy ? tr("Enemy %1").arg(name) : name;
        }
        else if (admin.hasAll<StationBodyComponent>(actor))
        {
            key = isEnemy ? QStringLiteral("station:enemy")
                          : QStringLiteral("station:player");
            label = isEnemy ? tr("Enemy Defence Station") : tr("Player Defence Station");
        }
        else
        {
            continue;
        }

        if (counts.find(key) == counts.end())
        {
            keys.push_back(key);
            labels[key] = label;
        }
        counts[key] += 1;
    }

    for (const QString& key : keys)
    {
        getRuntimeLayout()->addWidget(
            new CountRow(QPixmap(), labels[key], counts[key], this));
    }

    if (!m_debris.empty())
    {
        getRuntimeLayout()->addWidget(new CountRow(
            QPixmap(), tr("Debris"), static_cast<int>(m_debris.size()), this));

        // Indented under the debris row, so the total reads as belonging to it, and
        // stated in the same amount-plus-bare-icon form the debris card uses
        // (REQ-UI-DEBRIS-PANEL, REQ-UI-FIELD-MULTI-SELECTION).
        m_scrapRow = new StatRow(tr("holding"), this);
        m_scrapRow->setValueIcon(m_scrapIcon);
        m_scrapRow->setIndented(true);
        m_scrapRow->setValueEmphasized(true);
        // The same value as the debris card's, so it explains its item the same way
        // (REQ-UI-ITEM-VALUE-TOOLTIP).
        ItemTooltip::attachTo(m_scrapRow->getValueWidget(),
                              getContext().getItemTooltipContext(), kScrapItemId,
                              TooltipTrigger::Trigger::HoverAndClick);
        getRuntimeLayout()->addWidget(m_scrapRow);
    }
}

void FieldMultiContent::refreshRuntime()
{
    // The counts are fixed for a given selection -- an actor leaving it re-publishes the
    // selection and rebuilds this card -- but the scrap falls as the debris is collected.
    if (m_scrapRow)
    {
        const int scrap = sumDebrisScrap(getContext().sim->getAdmin(), m_debris);
        // The icon names the item; only without one does the value have to say the word.
        m_scrapRow->setValue(m_scrapIcon.isNull() ? tr("%1 scrap").arg(scrap)
                                                  : QString::number(scrap));
    }
}
