#include "CreateSnapshotWindow.hpp"

#include <QFile>
#include <QSize>
#include <QDesktopServices>

#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"

#include "src/Insight/InsightSignals.hpp"

#include "src/Services/PathService.hpp"
#include "src/Helpers/EnumToStringMappings.hpp"
#include "src/Exceptions/Exception.hpp"

namespace Widgets
{
    using Exceptions::Exception;

    CreateSnapshotWindow::CreateSnapshotWindow(
        const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor,
        const Targets::TargetMemorySegmentDescriptor& memorySegmentDescriptor,
        const Targets::TargetState& targetState,
        const std::optional<Targets::TargetMemoryBuffer>& data,
        const bool& staleData,
        QWidget* parent
    )
        : QWidget(parent)
        , addressSpaceDescriptor(addressSpaceDescriptor)
        , memorySegmentDescriptor(memorySegmentDescriptor)
        , targetState(targetState)
        , data(data)
        , staleData(staleData)
    {
        this->setWindowFlag(Qt::Window);
        this->setObjectName("create-snapshot-window");
        this->setWindowTitle(
            "New Snapshot - " + QString::fromStdString(this->memorySegmentDescriptor.name)
        );

        auto windowUiFile = QFile{
            QString::fromStdString(Services::PathService::compiledResourcesPath()
                + "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
                + "/SnapshotManager/CreateSnapshotWindow/UiFiles/CreateSnapshotWindow.ui"
            )
        };

        if (!windowUiFile.open(QFile::ReadOnly)) {
            throw Exception{"Failed to open CreateSnapshotWindow UI file"};
        }

        this->setFixedSize(QSize{500, 300});

        auto uiLoader = UiLoader{this};
        this->container = uiLoader.load(&windowUiFile, this);

        this->container->setFixedSize(this->size());
        this->container->setContentsMargins(15, 15, 15, 15);

        auto* formContainer = this->container->findChild<QWidget*>("form-container");

        this->nameInput = formContainer->findChild<TextInput*>("name-input");
        this->descriptionInput = formContainer->findChild<QPlainTextEdit*>("description-input");
        this->includeFocusedRegionsInput = formContainer->findChild<QCheckBox*>("include-focus-regions-input");
        this->captureDirectlyFromTargetInput = formContainer->findChild<QCheckBox*>("capture-directly-from-target-input");

        this->staleDataWarning = formContainer->findChild<QWidget*>("stale-data-warning");

        this->captureButton = this->container->findChild<PushButton*>("capture-btn");
        this->closeButton = this->container->findChild<PushButton*>("close-btn");

        QObject::connect(this->nameInput, &QLineEdit::textEdited, this, &CreateSnapshotWindow::refreshForm);
        QObject::connect(
            this->captureDirectlyFromTargetInput,
            &QCheckBox::stateChanged,
            this,
            &CreateSnapshotWindow::refreshForm
        );

        QObject::connect(this->captureButton, &QPushButton::clicked, this, &CreateSnapshotWindow::issueCaptureRequest);
        QObject::connect(this->closeButton, &QPushButton::clicked, this, &QWidget::close);

        QObject::connect(
            InsightSignals::instance(),
            &InsightSignals::targetStateUpdated,
            this,
            [this] () {
                this->refreshForm();
            }
        );

        this->includeFocusedRegionsInput->setChecked(true);
        this->captureDirectlyFromTargetInput->setChecked(false);
        this->resetForm();
    }

    void CreateSnapshotWindow::refreshForm() {
        this->captureButton->setEnabled(this->captureEnabled());
        this->staleDataWarning->setVisible(this->staleData && !this->captureDirectlyFromTargetInput->isChecked());
    }

    void CreateSnapshotWindow::showEvent(QShowEvent* event) {
        this->move(this->parentWidget()->window()->geometry().center() - this->rect().center());
        this->refreshForm();
        QWidget::showEvent(event);
    }

    void CreateSnapshotWindow::keyPressEvent(QKeyEvent* event) {
        const auto key = event->key();

        if (key == Qt::Key_Enter || key == Qt::Key_Return) {
            this->captureButton->click();
            return;
        }

        if (key == Qt::Key_Escape) {
            this->close();
            return;
        }

        QWidget::keyPressEvent(event);
    }

    bool CreateSnapshotWindow::captureEnabled() {
        if (this->targetState.executionState != Targets::TargetExecutionState::STOPPED) {
            return false;
        }

        if (!this->data.has_value() && !this->captureDirectlyFromTargetInput->isChecked()) {
            return false;
        }

        if (this->nameInput->text().isEmpty()) {
            return false;
        }

        return true;
    }

    void CreateSnapshotWindow::resetForm() {
        this->nameInput->setText("Untitled Snapshot");
        this->descriptionInput->setPlainText("");
    }

    void CreateSnapshotWindow::issueCaptureRequest() {
        if (!this->captureEnabled()) {
            // Sanity check
            this->refreshForm();
            return;
        }

        emit this->snapshotCaptureRequested(
            this->nameInput->text(),
            this->descriptionInput->toPlainText(),
            this->includeFocusedRegionsInput->isChecked(),
            this->captureDirectlyFromTargetInput->isChecked()
        );

        this->close();
        this->resetForm();
    }
}
