#include "visual_deck_editor_sample_hand_widget.h"

#include "../../../client/settings/cache_settings.h"
#include "../../deck_loader/deck_loader.h"
#include "../cards/card_info_picture_widget.h"
#include "../deck_analytics/analyzer_modules/draw_probability/draw_probability_widget.h"
#include "../deck_analytics/deck_list_statistics_analyzer.h"

#include <QSplitter>
#include <libcockatrice/card/database/card_database_manager.h>
#include <random>

VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *parent,
                                                                   DeckListModel *_deckListModel,
                                                                   DeckListStatisticsAnalyzer *_statsAnalyzer)
    : QWidget(parent), deckListModel(_deckListModel), statsAnalyzer(_statsAnalyzer)
{
    layout = new QVBoxLayout(this);
    layout->setSpacing(0);
    setLayout(layout);

    auto upperLayout = new QVBoxLayout();
    upperLayout->setContentsMargins(0, 0, 0, 0);
    upperLayout->setSpacing(0);

    resetAndHandSizeContainerWidget = new QWidget(this);
    resetAndHandSizeLayout = new QHBoxLayout(resetAndHandSizeContainerWidget);
    resetAndHandSizeLayout->setContentsMargins(11, 0, 11, 0);
    resetAndHandSizeContainerWidget->setLayout(resetAndHandSizeLayout);

    resetButton = new QPushButton(this);
    connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay()));
    resetAndHandSizeLayout->addWidget(resetButton);

    handSizeSpinBox = new QSpinBox(this);
    handSizeSpinBox->setValue(SettingsCache::instance().getVisualDeckEditorSampleHandSize());
    handSizeSpinBox->setMinimum(1);
    connect(handSizeSpinBox, qOverload<int>(&QSpinBox::valueChanged), &SettingsCache::instance(),
            &SettingsCache::setVisualDeckEditorSampleHandSize);
    connect(handSizeSpinBox, qOverload<int>(&QSpinBox::valueChanged), this,
            &VisualDeckEditorSampleHandWidget::updateDisplay);
    resetAndHandSizeLayout->addWidget(handSizeSpinBox);

    upperLayout->addWidget(resetAndHandSizeContainerWidget);

    flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
    upperLayout->addWidget(flowWidget);

    cardSizeWidget = new CardSizeWidget(this, flowWidget);
    upperLayout->addWidget(cardSizeWidget);

    auto upperLayoutWidget = new QWidget(this);
    upperLayoutWidget->setLayout(upperLayout);

    drawProbabilityWidget = new DrawProbabilityWidget(this, statsAnalyzer);

    auto *splitter = new QSplitter(this);
    splitter->setObjectName("splitter");
    splitter->setOrientation(Qt::Vertical);

    splitter->addWidget(upperLayoutWidget);
    splitter->addWidget(drawProbabilityWidget);

    layout->addWidget(splitter);

    retranslateUi();
}

void VisualDeckEditorSampleHandWidget::retranslateUi()
{
    resetButton->setText(tr("Draw a new sample hand"));
    handSizeSpinBox->setToolTip(tr("Sample hand size"));
}

void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
{
    deckListModel = deckModel;
    // connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorSampleHandWidget::updateDisplay);
    updateDisplay();
}

void VisualDeckEditorSampleHandWidget::updateDisplay()
{
    flowWidget->clearLayout();
    for (const ExactCard &card : getRandomCards(handSizeSpinBox->value())) {
        auto displayWidget = new CardInfoPictureWidget(this);
        displayWidget->setCard(card);
        displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
        connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, displayWidget,
                &CardInfoPictureWidget::setScaleFactor);
        flowWidget->addWidget(displayWidget);
    }
}

static QList<ExactCard> cardNodesToExactCards(QList<const DecklistCardNode *> nodes)
{
    QList<ExactCard> cards;
    for (auto node : nodes) {
        ExactCard card = CardDatabaseManager::query()->getCard(node->toCardRef());
        if (card) {
            for (int k = 0; k < node->getNumber(); ++k) {
                cards.append(card);
            }
        } else {
            qDebug() << "Card not found in database!";
        }
    }

    return cards;
}

QList<ExactCard> VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGet)
{
    QList<ExactCard> randomCards;
    if (!deckListModel) {
        return randomCards;
    }

    QList<ExactCard> mainDeckCards = cardNodesToExactCards(deckListModel->getCardNodesForZone(DECK_ZONE_MAIN));

    if (mainDeckCards.isEmpty()) {
        return randomCards;
    }

    // Shuffle the deck
    std::random_device rd;
    std::mt19937 rng(rd());
    std::shuffle(mainDeckCards.begin(), mainDeckCards.end(), rng);

    // Select amountToGet cards

    for (int i = 0; i < qMin(amountToGet, mainDeckCards.size()); ++i) {
        randomCards.append(mainDeckCards.at(i));
    }

    std::sort(randomCards.begin(), randomCards.end(),
              [](const ExactCard &a, const ExactCard &b) { return a.getInfo().getCmc() < b.getInfo().getCmc(); });

    return randomCards;
}
