#include <QtWidgets/QApplication>
#include <QDebug>
#include <QTcpSocket>
#include <QMessageBox>
#include <QSettings>
#include <QtSerialPort/QtSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QCommandLineParser>
#include <csignal>

#include "ui/mainwindow.h"
#include "items/itemstore.h"
#include "mainobject.h"
#include "programmode.h"

void sigHandler(int s)
{
	std::signal(s, SIG_DFL);
	QCoreApplication *app = QCoreApplication::instance();
	if(app)
		 app->quit();
}

int main(int argc, char *argv[])
{
	QCoreApplication::setOrganizationName("UVOS");
	QCoreApplication::setOrganizationDomain("uvos.xyz");
	QCoreApplication::setApplicationName("SHinterface");
	QCoreApplication::setApplicationVersion("0.6");

	QStringList args;
	for(int i = 0; i < argc; ++i)
		args<<argv[i];

	//parse comand line
	QCommandLineParser parser;
	parser.setApplicationDescription("Smart Home Interface");
	parser.addHelpOption();
	parser.addVersionOption();
	QCommandLineOption masterOption(QStringList() << "m" << "master", QCoreApplication::translate("main", "Use in master mode"));
	parser.addOption(masterOption);
	QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main", "Set server host ip addres"), "address", "0.0.0.0");
	parser.addOption(hostOption);
	QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main", "Set server Port"), "port", "38940");
	parser.addOption(portOption);
	QCommandLineOption settingsPathOption(QStringList()<<"c"<<"config", QCoreApplication::translate("main", "Set config file"), "configFilePath",
										  QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/shinterface.json");
	parser.addOption(settingsPathOption);
	QCommandLineOption headlessOption(QStringList()<<"e"<<"headless", QCoreApplication::translate("main", "Dont start the gui"));
	parser.addOption(headlessOption);

	parser.process(args);

	programMode = PROGRAM_MODE_UI_ONLY;
	if(parser.isSet(masterOption))
	{
		programMode = PROGRAM_MODE_PRIMARY;
		if(parser.isSet(headlessOption))
			programMode = PROGRAM_MODE_HEADLESS_PRIMARY;
	}

	QCoreApplication* a;
	if(programMode == PROGRAM_MODE_HEADLESS_PRIMARY)
		a = new QCoreApplication(argc, argv);
	else
		a = new QApplication(argc, argv);

	int retVal;

	std::signal(SIGINT,  sigHandler);
	std::signal(SIGTERM, sigHandler);
	std::signal(SIGHUP, sigHandler);

	QString uiSettingsPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/smartvos_ui.json";

	if(programMode == PROGRAM_MODE_PRIMARY || programMode == PROGRAM_MODE_HEADLESS_PRIMARY)
	{
		QString settingsPath = parser.value(settingsPathOption);
		QJsonObject json = MainObject::getJsonObjectFromDisk(settingsPath);
		bool tcpMicro = json["MicroTcp"].toBool(true);
		json["MicroTcp"] = tcpMicro;

		QIODevice* microDevice = nullptr;
		if(tcpMicro)
		{
			int port = json["MicroTcpPort"].toInt(6856);
			json["MicroTcpPort"] = port;
			QString host = json["MicroTcpHost"].toString("127.0.0.1");
			json["MicroTcpHost"] = host;

			QTcpSocket* microSocket = new QTcpSocket;

			qInfo()<<"connecting to "<<host<<':'<<port<<" for tcp micro";
			microSocket->connectToHost(host, port, QIODevice::ReadWrite);

			if(!microSocket->waitForConnected(1000))
			{
				qCritical()<<"Can not connect to tcp micro";
				MainObject::storeJsonObjectToDisk(settingsPath, json);
				if(programMode == PROGRAM_MODE_PRIMARY)
					QMessageBox::critical(nullptr, "Error", "Can not connect to tcp micro");
				return 1;
			}
			microDevice = microSocket;
		}
		else
		{
			QString port = json["MicroSerialPort"].toString("ttyUSB0");
			json["MicroSerialPort"] = port;
			int baud = json["MicroSerialBaud"].toInt(38400);
			json["MicroSerialBaud"] = baud;

			QSerialPort *microPort = new QSerialPort;
			microPort->setPortName(port);
			microPort->setBaudRate(baud);
			microPort->open(QIODevice::ReadWrite);

			if(!microPort->isOpen())
			{
				qCritical()<<"Can not open serial port"<<port;
				MainObject::storeJsonObjectToDisk(settingsPath, json);
				if(programMode == PROGRAM_MODE_PRIMARY)
					QMessageBox::critical(nullptr, "Error", "Can not open serial port " + port);
				return 1;
			}
			microDevice = microPort;
		}
		PrimaryMainObject mainObject(microDevice, settingsPath, parser.value(hostOption), parser.value(portOption).toInt());
		MainWindow* w = nullptr;
		if(programMode != PROGRAM_MODE_HEADLESS_PRIMARY)
		{
			w = new MainWindow(&mainObject);
			QJsonObject uiSettings = MainObject::getJsonObjectFromDisk(uiSettingsPath);
			w->load(uiSettings);

			QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), w, SLOT(changeHeaderLableText(QString)));
			QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), w, SLOT(changeHeaderLableText(QString)));
			QObject::connect(w, &MainWindow::sigSetRgb, &mainObject.micro, &Microcontroller::changeRgbColor);
			QObject::connect(w, &MainWindow::sigSave, &mainObject, [&mainObject, settingsPath](){mainObject.storeToDisk(settingsPath);});
			QObject::connect(w, &MainWindow::createdItem, &globalItems, &ItemStore::addItem);
			w->show();
		}

		retVal = a->exec();

		if(programMode != PROGRAM_MODE_HEADLESS_PRIMARY)
		{
			QJsonObject uiSettingsJson;
			w->store(uiSettingsJson);
			MainObject::storeJsonObjectToDisk(uiSettingsPath, uiSettingsJson);
		}

		delete w;
		delete microDevice;
	}
	else
	{
		SecondaryMainObject mainObject(parser.value(hostOption), parser.value(portOption).toInt());
		MainWindow w(&mainObject);
		QJsonObject uiSettings = MainObject::getJsonObjectFromDisk(uiSettingsPath);
		w.load(uiSettings);

		QObject::connect(&w, &MainWindow::createdItem, &globalItems, &ItemStore::addItem);
		QObject::connect(&w, &MainWindow::sigSave, mainObject.tcpClient, &TcpClient::sendItems);

		w.show();

		retVal = a->exec();

		QJsonObject uiSettingsJson;
		w.store(uiSettingsJson);
		MainObject::storeJsonObjectToDisk(uiSettingsPath, uiSettingsJson);
	}

	delete a;

	return retVal;
}

