#include "RecipeSelectionDialog.h"

#include <cstddef>

#include <QGridLayout>
#include <QIcon>
#include <QPixmap>
#include <QPushButton>
#include <QSize>
#include <QStringList>
#include <QVBoxLayout>

#include "Building.h"
#include "BuildingType.h"
#include "DisplayName.h"
#include "GameConfig.h"
#include "ItemIconCache.h"
#include "RecipesConfig.h"
#include "RecipeTooltip.h"
#include "ShipsConfig.h"
#include "Simulation.h"

namespace
{

QString itemLine(const std::string& itemId, int amount)
{
    return QStringLiteral("  ")
        + QString::fromStdString(toDisplayName(itemId))
        + QStringLiteral(" x ") + QString::number(amount);
}

QString shipTooltip(const ShipDef& def)
{
    const QString name = QString::fromStdString(toDisplayName(def.id));

    QStringList lines;
    lines << QObject::tr("Ship: %1").arg(name);

    if (def.schematic.materials.empty())
    {
        lines << QObject::tr("Materials: none");
    }
    else
    {
        lines << QObject::tr("Materials:");
        for (const RecipeIngredient& material : def.schematic.materials)
        {
            lines << itemLine(material.item, material.amount);
        }
        lines << QObject::tr("  + installed modules");
    }

    lines << QObject::tr("Completion time: %1 s")
        .arg(def.schematic.productionTimeSeconds);
    lines << QObject::tr("Produces: 1 %1").arg(name);

    return lines.join('\n');
}

}  // namespace

std::vector<RecipeSelectionOption> buildRecipeSelectionOptions(
    BuildingType type, Simulation& sim, const GameConfig& config)
{
    std::vector<RecipeSelectionOption> options;
    options.push_back({std::string(), QObject::tr("(None)"), QString()});

    if (type == BuildingType::Shipyard)
    {
        for (const ShipDef& def : config.ships.ships)
        {
            if (!sim.isSchematicUnlocked(def.id)) { continue; }
            options.push_back({def.id,
                               QString::fromStdString(toDisplayName(def.id)),
                               shipTooltip(def)});
        }
    }
    else
    {
        for (const RecipeDef& recipe : config.recipes.recipes)
        {
            if (recipe.building != type) { continue; }
            if ((type == BuildingType::Miner
                 || type == BuildingType::Assembler)
                && !sim.isRecipeUnlocked(recipe.id))
            {
                continue;
            }
            // Icon shown on the option button (REQ-UI-RECIPE-ICON): the recipe's
            // configured icon item, else its first output item.
            const std::string iconItemId = recipe.icon
                ? *recipe.icon
                : (recipe.outputs.empty() ? std::string()
                                          : recipe.outputs.front().item);
            options.push_back({recipe.id,
                               QString::fromStdString(toDisplayName(recipe.id)),
                               buildRecipeTooltip(recipe),
                               iconItemId});
        }
    }

    return options;
}

namespace
{
    // On-screen size of a recipe option button's item icon (REQ-UI-RECIPE-ICON).
    const QSize kOptionIconSize(32, 32);
}

RecipeSelectionDialog::RecipeSelectionDialog(
    const std::vector<RecipeSelectionOption>& options,
    const QString& title, ItemIconCache* itemIcons, QWidget* parent)
    : QDialog(parent)
{
    setWindowTitle(title);
    setModal(true);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    QGridLayout* grid = new QGridLayout();
    mainLayout->addLayout(grid);

    const int columnCount = 2;
    for (int i = 0; i < static_cast<int>(options.size()); ++i)
    {
        const RecipeSelectionOption& option = options[static_cast<std::size_t>(i)];

        QPushButton* button = new QPushButton(this);
        // Icon-only when the produced item has an icon (REQ-UI-RECIPE-ICON); otherwise
        // fall back to the caption. The name stays reachable via the tooltip.
        if (!option.iconItemId.empty() && itemIcons->hasIcon(option.iconItemId))
        {
            button->setIcon(QIcon(itemIcons->getPixmap(
                option.iconItemId, kOptionIconSize.width())));
            button->setIconSize(kOptionIconSize);
        }
        else
        {
            button->setText(option.caption);
        }
        if (!option.tooltip.isEmpty())
        {
            button->setToolTip(option.tooltip);
        }
        button->setMinimumHeight(40);
        grid->addWidget(button, i / columnCount, i % columnCount);

        m_optionIds.push_back(option.id);
        const int index = i;
        connect(button, &QPushButton::clicked, this, [this, index]()
        {
            onOptionClicked(index);
        });
    }
}

std::optional<std::string> RecipeSelectionDialog::getChosenId() const
{
    return m_chosenId;
}

void RecipeSelectionDialog::onOptionClicked(int index)
{
    if (index >= 0 && index < static_cast<int>(m_optionIds.size()))
    {
        m_chosenId = m_optionIds[static_cast<std::size_t>(index)];
    }
    accept();
}
