#include "SchematicChoiceDialog.h"

#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

#include "DisplayName.h"
#include "RecipeLineRow.h"
#include "RecipesConfig.h"

namespace
{

std::vector<RecipeLineRow::Amount> toAmounts(
    const std::vector<RecipeIngredient>& ingredients)
{
    std::vector<RecipeLineRow::Amount> amounts;
    amounts.reserve(ingredients.size());
    for (const RecipeIngredient& ingredient : ingredients)
    {
        amounts.push_back(RecipeLineRow::Amount{ ingredient.item, ingredient.amount });
    }
    return amounts;
}

std::vector<RecipeLineRow::Amount> toAmounts(const std::vector<RecipeOutput>& outputs)
{
    std::vector<RecipeLineRow::Amount> amounts;
    amounts.reserve(outputs.size());
    for (const RecipeOutput& output : outputs)
    {
        amounts.push_back(RecipeLineRow::Amount{ output.item, output.amount });
    }
    return amounts;
}

QString grantKindLabel(SchematicType type)
{
    switch (type)
    {
    case SchematicType::Ship:     return SchematicChoiceDialog::tr("Ship");
    case SchematicType::Module:   return SchematicChoiceDialog::tr("Module");
    case SchematicType::Building: return SchematicChoiceDialog::tr("Building");
    case SchematicType::Recipe:   return SchematicChoiceDialog::tr("Recipe");
    }
    return QString();
}

}  // namespace

SchematicChoiceDialog::SchematicChoiceDialog(
    const std::vector<SchematicChoiceOption>& options,
    const RecipesConfig& recipes, ItemIconCache* itemIcons,
    BuildingIconCache* buildingIcons,
    QWidget* parent)
    : QDialog(parent)
    , m_chosenIndex(0)
{
    setWindowTitle(tr("Schematic Drop"));
    setWindowFlags(windowFlags() & ~Qt::WindowCloseButtonHint);
    setModal(true);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);

    QLabel* titleLabel = new QLabel(tr("Choose a schematic to unlock:"), this);
    QFont titleFont = titleLabel->font();
    titleFont.setPointSize(titleFont.pointSize() + 2);
    titleFont.setBold(true);
    titleLabel->setFont(titleFont);
    titleLabel->setAlignment(Qt::AlignCenter);
    mainLayout->addWidget(titleLabel);

    QHBoxLayout* optionsLayout = new QHBoxLayout();
    mainLayout->addLayout(optionsLayout);

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

        QWidget* card = new QWidget(this);
        QVBoxLayout* cardLayout = new QVBoxLayout(card);
        // Scoped to the card by object name. An unscoped "QWidget" selector cascades to
        // every descendant, which boxed each label and each icon of the recipe lines
        // inside it as well.
        card->setObjectName(QStringLiteral("schematicChoiceCard"));
        card->setStyleSheet(QStringLiteral(
            "QWidget#schematicChoiceCard { border: 1px solid gray; padding: 8px; }"));

        QLabel* nameLabel = new QLabel(QString::fromStdString(option.displayName), card);
        QFont nameFont = nameLabel->font();
        nameFont.setPointSize(nameFont.pointSize() + 1);
        nameFont.setBold(true);
        nameLabel->setFont(nameFont);
        nameLabel->setAlignment(Qt::AlignCenter);
        cardLayout->addWidget(nameLabel);

        if (option.isArtifact)
        {
            QLabel* artifactTypeLabel = new QLabel(tr("Artifact"), card);
            artifactTypeLabel->setAlignment(Qt::AlignCenter);
            cardLayout->addWidget(artifactTypeLabel);
        }
        else
        {
            QLabel* grantsHeaderLabel = new QLabel(tr("Unlocks:"), card);
            QFont grantsHeaderFont = grantsHeaderLabel->font();
            grantsHeaderFont.setBold(true);
            grantsHeaderLabel->setFont(grantsHeaderFont);
            grantsHeaderLabel->setAlignment(Qt::AlignCenter);
            cardLayout->addWidget(grantsHeaderLabel);

            for (const GrantedSchematic& grant : option.grantedItems)
            {
                QLabel* grantLabel = new QLabel(
                    grantKindLabel(grant.type) + ": "
                        + QString::fromStdString(grant.displayName),
                    card);
                grantLabel->setAlignment(Qt::AlignCenter);
                cardLayout->addWidget(grantLabel);
            }

            QLabel* unlocksHeaderLabel = new QLabel(tr("Unlocks recipes:"), card);
            QFont unlocksHeaderFont = unlocksHeaderLabel->font();
            unlocksHeaderFont.setBold(true);
            unlocksHeaderLabel->setFont(unlocksHeaderFont);
            unlocksHeaderLabel->setAlignment(Qt::AlignCenter);
            cardLayout->addWidget(unlocksHeaderLabel);

            if (option.newlyUnlockedRecipeIds.empty())
            {
                QLabel* noneLabel = new QLabel(tr("None"), card);
                noneLabel->setAlignment(Qt::AlignCenter);
                cardLayout->addWidget(noneLabel);
            }
            else
            {
                for (const std::string& recipeId : option.newlyUnlockedRecipeIds)
                {
                    const RecipeDef* def = recipes.findRecipeDef(recipeId);
                    if (def == nullptr) { continue; }

                    // The recipe drawn as it is everywhere else, led by the building
                    // that runs it and its name, so the line says everything there is
                    // to say about it and carries no tooltip (REQ-DEF-SCHEMATIC-DROP).
                    RecipeLineRow::Spec spec;
                    spec.building        = def->building;
                    spec.name            = QString::fromStdString(toDisplayName(def->id));
                    spec.inputs          = toAmounts(def->inputs);
                    spec.outputs         = toAmounts(def->outputs);
                    spec.durationSeconds = def->durationSeconds;

                    RecipeLineRow* line =
                        new RecipeLineRow(itemIcons, buildingIcons, card);
                    line->setCardChrome(true);
                    cardLayout->addWidget(line);
                    line->setLine(spec);
                }
            }
        }

        QPushButton* selectButton = new QPushButton(tr("Select"), card);
        cardLayout->addWidget(selectButton);

        const int index = i;
        connect(selectButton, &QPushButton::clicked, this, [this, index]()
        {
            onOptionClicked(index);
        });

        optionsLayout->addWidget(card);
    }
}

int SchematicChoiceDialog::getChosenIndex() const
{
    return m_chosenIndex;
}

void SchematicChoiceDialog::onOptionClicked(int index)
{
    m_chosenIndex = index;
    accept();
}
