#include "ShipyardContent.h"

#include <QPushButton>
#include <QVBoxLayout>

#include "BuildingTarget.h"
#include "EventManager.h"
#include "GameConfig.h"
#include "LayoutDialogRequestedEvent.h"
#include "ProductionRules.h"
#include "RecipeSelectionControl.h"
#include "SectionBox.h"
#include "ShipLayoutPreview.h"

ShipyardContent::ShipyardContent(const SelectionContext& context,
                                 const SelectionRequest& request, QWidget* parent)
    : BufferedBuildingContent(context, request.buildings.front(), parent)
{
    m_schematicControl = new RecipeSelectionControl(context, getBuildingId(),
                                                    BuildingType::Shipyard, this);

    m_layoutSection   = new SectionBox(tr("Layout"), this);
    m_layoutPreview   = new ShipLayoutPreview(m_layoutSection);
    m_configureButton = new QPushButton(tr("Configure Layout"), m_layoutSection);
    m_layoutSection->getContentLayout()->addWidget(m_layoutPreview);
    m_layoutSection->getContentLayout()->addWidget(m_configureButton);

    // Ahead of the recipe summary the base adds, so the card reads schematic, layout,
    // then what one ship costs.
    getConfigurationLayout()->insertWidget(0, m_schematicControl);
    getConfigurationLayout()->insertWidget(1, m_layoutSection);

    const BuildingId id = getBuildingId();
    connect(m_configureButton, &QPushButton::clicked, this, [id]() {
        EventManager::getInstance()->sendEventImmediately(
            std::make_shared<LayoutDialogRequestedEvent>(id));
    });
}

void ShipyardContent::refreshControls(const BuildingTarget& target)
{
    m_schematicControl->setRecipeId(target.recipeId);

    // The preview and Configure button are always shown for a shipyard and are only
    // enabled once a schematic is selected (REQ-MOD-UI-PREVIEW). The schematic arrives
    // by queued command, so this refresh is what picks it up rather than the click that
    // chose it. Same question the dialog's own entry points ask, asked once.
    const ShipDef* shipDef =
        getContext().config->ships.findLayoutShipDef(target.recipeId);
    const bool hasSchematic = shipDef != nullptr;
    if (hasSchematic)
    {
        m_layoutPreview->setShipAndLayout(
            shipDef->layout,
            target.shipLayout.has_value() ? *target.shipLayout : ShipLayoutConfig(),
            &getContext().config->modules);
    }
    else
    {
        m_layoutPreview->showPlaceholder();
    }
    m_layoutPreview->setEnabled(hasSchematic);
    m_configureButton->setEnabled(hasSchematic);
}

BufferedBuildingContent::CycleInfo ShipyardContent::getCycleInfo(
    const BuildingTarget& target) const
{
    CycleInfo info;
    const ShipDef* shipDef = target.recipeId.empty()
        ? nullptr
        : getContext().config->ships.findShipDef(target.recipeId);
    if (!shipDef)
    {
        return info;
    }

    // The schematic's materials plus every placed module's, which is also what sized the
    // input buffers (REQ-BLD-SHIPYARD). The simulation owns that sum, so the panel asks
    // it rather than adding the modules up a second time.
    info.perCycleInputs = computeShipyardRequiredMaterials(
        *getContext().config, target.recipeId, target.shipLayout);

    // A shipyard's output is the ship itself, which never lands in an item buffer -- so
    // the summary shows no output item at all. The time is the schematic's plus its
    // modules', from the same place the layout dialog's build cost reads it
    // (REQ-MOD-PRODUCTION-TIME).
    info.durationSeconds = computeShipyardProductionTimeSeconds(
        *getContext().config, target.recipeId, target.shipLayout);
    info.runsProduction = true;
    return info;
}
