#pragma once

#include <cstddef>
#include <cstdint>
#include <iostream>
#include <optional>
#include <vector>

#include <QApplication>
#include <QCloseEvent>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QIcon>
#include <QMainWindow>
#include <QMdiSubWindow>
#include <QMessageBox>

#include "../ui/ui_about.h"
#include "../ui/ui_license.h"
#include "../ui/ui_mapprops.h"
#include "../ui/ui_menu.h"
#include "../ui/ui_project.h"

#include "bindings.h"

#pragma clang diagnostic warning "-Winconsistent-missing-override"

class Project;

using byte = std::uint8_t;

class MapModel final : public IMapModel
{
	Q_OBJECT

public:
	explicit MapModel(Project *parent);
	~MapModel() override;

public slots:
	void deselect() override;
	void select(QModelIndex const &index) override;

private:
	QVariant data(const QModelIndex &index, int role) const override;
};

class MapView final : public IMapView
{
	Q_OBJECT

public:
	explicit MapView(Project *parent);
	~MapView();

private:
	MapModel *const m_mapModel;
};

class MapProps final : public  QDialog,
                       private Ui::MapProps
{
	Q_OBJECT

public:
	explicit MapProps(Project *parent);
	~MapProps();

	void accept() override;

private:
	MapModel *const m_mapModel;
};

class Menu final : public  QMainWindow,
                   private Ui::Menu
{
	Q_OBJECT

public:
	explicit Menu(QWidget *parent = nullptr);
	~Menu();

public slots:
	void mapNew();
	void mapOpen();
	void openAbout();
	void openAboutQt();
	void openMapProperties();
	void updateActions();

protected:
	void closeEvent(QCloseEvent *event) override;
	void openLicense(QWidget *parent);

private:
	Project       *activeProject() const;
	QMdiSubWindow *activeSubWindow() const;

	void addProject(Project *proj);
};

class Project final : public  QMdiSubWindow,
                      private Ui::Project
{
	Q_OBJECT
	Q_PROPERTY(Type           type     READ type     CONSTANT)
	Q_PROPERTY(IProjectModel *model    READ model    CONSTANT)
	Q_PROPERTY(MapModel      *mapModel READ mapModel CONSTANT)

public:
	enum Type {Map};
	Q_ENUM(Type)

	explicit Project(Type type);
	~Project();

	Type type() const;
	IProjectModel *model() const;
	MapModel *mapModel() const;

protected:
	void closeEvent(QCloseEvent *event) override;

private:
	Type           const m_type;
	IProjectModel *const m_model;
	IProjectView  *const m_view;
};

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"

template<typename... VA>
static inline
void dbgPrint([[maybe_unused]] char const *fmt, [[maybe_unused]] VA &&...va)
{
	#ifdef TYCHO_DEBUG_ASSERTIONS
	qDebug(fmt, std::forward<VA>(va)...);
	#endif
}

#pragma clang diagnostic pop

#define dbgPrintFunc() dbgPrint("%s", __func__)

constexpr
std::uint32_t fourCC(byte a, byte b, byte c, byte d)
{
	return (static_cast<std::uint32_t>(a) << 24) |
	       (static_cast<std::uint32_t>(b) << 16) |
	       (static_cast<std::uint32_t>(c) <<  8) |
	        static_cast<std::uint32_t>(d);
}

QIcon getIcon(QString const &name);

extern "C" {
	char const *tychoAuthors();
	char const *tychoHomepage();
	char const *tychoLicenseText();
	char const *tychoRepository();
	char const *tychoVersion();
}

// EOF
