#include "HeaderBar.h"

#include <cmath>
#include <string>

#include <QHBoxLayout>
#include <QLabel>
#include <QPalette>
#include <QPushButton>
#include <QSignalMapper>

#include "EventManager.h"
#include "IconCaption.h"
#include "ItemIconCache.h"
#include "ItemTooltip.h"
#include "Simulation.h"
#include "SpeedChangeRequestedEvent.h"
#include "Tick.h"
#include "TooltipTrigger.h"

const double HeaderBar::kSpeeds[]   = { 0.0, 0.5, 1.0, 2.0, 10.0 };
const int    HeaderBar::kSpeedCount = 5;

HeaderBar::HeaderBar(const ItemTooltipContext& context, QWidget* parent)
    : QWidget(parent)
    , m_context(context)
{
    QHBoxLayout* layout = new QHBoxLayout(this);
    layout->setContentsMargins(8, 4, 8, 4);
    layout->setSpacing(8);

    m_timeLabel      = new QLabel("00:00", this);
    // Both displays state a value and do nothing when clicked, so a click brings the
    // tooltip up at once rather than waiting the hover out (REQ-UI-TOOLTIP-TRIGGER).
    // The stock states an amount of an item, so what it shows is that item's production
    // tooltip, as every other display naming an item does
    // (REQ-UI-BLOCKS-ICON, REQ-UI-ITEM-VALUE-TOOLTIP).
    m_blocksLabel    = new QLabel(this);
    ItemTooltip::attachTo(*m_blocksLabel, m_context, kBlockItemId,
                          TooltipTrigger::Trigger::HoverAndClick);
    updateBlocksLabel();
    // An artifact count is no item amount, so it has no production path to show and
    // states configured text instead (REQ-UI-ARTIFACTS-TOOLTIP).
    m_artifactsLabel = new QLabel(tr("Artifacts: 0/?"), this);
    if (m_context.config->world.artifactTooltip)
    {
        TooltipTrigger::attachText(
            *m_artifactsLabel,
            QString::fromStdString(*m_context.config->world.artifactTooltip),
            TooltipTrigger::Trigger::HoverAndClick);
    }
	m_bossWaveLabel = new QLabel(tr("Boss Wave #1"), this);
	m_nextBossLabel = new QLabel(tr("Next boss: 5:00"), this);

	const int itemSpacing = 20;

	layout->addWidget(m_timeLabel);
	layout->addSpacing(itemSpacing);
	layout->addWidget(m_blocksLabel);
	layout->addSpacing(itemSpacing);
	layout->addWidget(m_artifactsLabel);
	layout->addStretch();
	layout->addWidget(m_bossWaveLabel);
	layout->addSpacing(itemSpacing);
	layout->addWidget(m_nextBossLabel);
	layout->addSpacing(itemSpacing);

    const char* labels[] = { "0x", "0.5x", "1x", "2x", "10x" };
    QSignalMapper* mapper = new QSignalMapper(this);
    for (int i = 0; i < kSpeedCount; ++i)
    {
        QPushButton* btn = new QPushButton(labels[i], this);
        btn->setCheckable(true);
        btn->setChecked(i == 2);
        layout->addWidget(btn);
        m_speedButtons.push_back(btn);
        mapper->setMapping(btn, i);
        connect(btn, &QPushButton::clicked, mapper, qOverload<>(&QSignalMapper::map));
    }
    connect(mapper, qOverload<int>(&QSignalMapper::mapped), this, &HeaderBar::onSpeedButton);

    setFixedHeight(sizeHint().height());

    registerForEvents();
}

HeaderBar::~HeaderBar()
{
    unregisterForEvents();
}

void HeaderBar::handleEvent(std::shared_ptr<const TickAdvancedEvent> /*event*/)
{
    const int totalSeconds = static_cast<int>(ticksToSeconds(m_context.sim->getCurrentTick()));
    m_timeLabel->setText(
        QString("%1:%2")
            .arg(totalSeconds / 60, 2, 10, QChar('0'))
            .arg(totalSeconds % 60, 2, 10, QChar('0')));
}

void HeaderBar::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> /*event*/)
{
    updateBlocksLabel();
}

void HeaderBar::updateBlocksLabel()
{
    const int blocks = m_context.sim->getBuildingBlocksStock();

    const QPixmap icon = m_context.itemIcons->getInlineIcon(kBlockItemId, font());
    if (icon.isNull())
    {
        // Fallback text form when no building_block icon exists (REQ-UI-BLOCKS-ICON).
        m_blocksLabel->setText(tr("Stock: %1 Blocks").arg(blocks));
        return;
    }
    m_blocksLabel->setPixmap(renderCaptionWithIcon(
        tr("Stock: %1").arg(blocks), icon, font(),
        m_blocksLabel->palette().color(QPalette::WindowText)));
}

void HeaderBar::handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event)
{
    for (int i = 0; i < kSpeedCount; ++i)
    {
        m_speedButtons[static_cast<std::size_t>(i)]->setChecked(
            std::abs(kSpeeds[i] - event->speed) < 0.001);
    }
}

void HeaderBar::handleEvent(std::shared_ptr<const BossWaveUpdatedEvent> /*event*/)
{
    const Tick countdownTicks = m_context.sim->getBossCountdownTicks();
    const int  bossSeconds    = static_cast<int>(
        ticksToSeconds(countdownTicks > 0 ? countdownTicks : 0));
	m_bossWaveLabel->setText(
		tr("Boss Wave #%1")
		.arg(m_context.sim->getBossWaveCounter()));
	m_nextBossLabel->setText(
		tr("Next boss: %1:%2")
		.arg(bossSeconds / 60)
		.arg(bossSeconds % 60, 2, 10, QChar('0')));
}

void HeaderBar::handleEvent(std::shared_ptr<const ArtifactCountChangedEvent> /*event*/)
{
    m_artifactsLabel->setText(
        tr("Artifacts: %1/%2")
            .arg(m_context.sim->getArtifactCount())
            .arg(m_context.sim->getConfig().world.artifacts.artifactWinCount));
}

void HeaderBar::onSpeedButton(int index)
{
    if (index >= 0 && index < kSpeedCount)
    {
        EventManager::getInstance()->sendEventImmediately(
            std::make_shared<SpeedChangeRequestedEvent>(kSpeeds[index]));
    }
}
