#include "databaselms.h"

#include <QtSql>
#include <QSqlDatabase>
#include <QSqlDriver>
#include <QDomDocument>
#include <QProcess>

bool DataBaseLMS::setUserPasswordPostgres(QString userName, QString password)
{
    DataBaseSettings settings = getDataBaseSettings();
    QSqlDatabase dbCheck = QSqlDatabase::addDatabase("QPSQL");

    dbCheck.setUserName(userName);
    dbCheck.setPassword(password);
    dbCheck.setHostName(settings.dbHostName);
    dbCheck.setPort(settings.dbPort);

    if (dbCheck.open())
    {
        UserNamePostgres = userName;
        PasswordPostgres = password;

        dbCheck.close();
        return true;
    }
    else
    {
        qDebug() << "PostgreSQL connection error.";
        return false;
    }
}

bool DataBaseLMS::checkDriverQPSQLavailable()
{
    return QSqlDatabase::isDriverAvailable("QPSQL");
}

bool DataBaseLMS::checkUserLMSexist()
{
    DataBaseSettings settings = getDataBaseSettings();
    QSqlDatabase dbCheck = QSqlDatabase::addDatabase("QPSQL");

    dbCheck.setUserName(UserNamePostgres);
    dbCheck.setPassword(PasswordPostgres);
    dbCheck.setHostName(settings.dbHostName);
    dbCheck.setPort(settings.dbPort);

    if (dbCheck.open())
    {
        QSqlQuery query = QSqlQuery(dbCheck);
        query.prepare("SELECT 1 FROM pg_roles WHERE rolname = :username");
        query.bindValue(":username", settings.dbUserName);

        if (query.exec() && query.next())
        {
            qDebug() << "The user exists.";
            return true;
        }
        else
        {
            qDebug() << "The user does not exist.";
            return false;
        }
    }
    else
    {
        qDebug() << "PostgreSQL connection error.";
        return false;
    }
}

bool DataBaseLMS::checkDataBaseLMSexist()
{
    DataBaseSettings settings = getDataBaseSettings();
    QSqlDatabase dbCheck = QSqlDatabase::addDatabase("QPSQL");

    bool flDBexist = false;

    dbCheck.setUserName(UserNamePostgres);
    dbCheck.setPassword(PasswordPostgres);
    dbCheck.setHostName(settings.dbHostName);
    dbCheck.setPort(settings.dbPort);

    if (dbCheck.open())
    {
        QString queryStr = QString("SELECT datname FROM pg_database");
        QSqlQuery query = QSqlQuery(dbCheck);

        if(queryExec(queryStr, &query))
        {
            while (query.next())
            {
                QString nameDB = "";
                nameDB = query.value(0).toString();
                if(nameDB == dbSettings.dbName)
                {
                    flDBexist = true;
                    break;
                }
            }
        }
    }
    else
    {
        qDebug() << "PostgreSQL connection error.";
        return false;
    }
    return flDBexist;
}

bool DataBaseLMS::createUser()
{
    DataBaseSettings settings = getDataBaseSettings();
    QSqlDatabase dbCheck = QSqlDatabase::addDatabase("QPSQL");

    dbCheck.setUserName(UserNamePostgres);
    dbCheck.setPassword(PasswordPostgres);
    dbCheck.setHostName(settings.dbHostName);
    dbCheck.setPort(settings.dbPort);

    if (dbCheck.open())
    {
        QString queryStr = QString("CREATE USER %1 WITH ENCRYPTED PASSWORD '%2'").arg(settings.dbUserName, settings.dbPassword);
        QSqlQuery query = QSqlQuery(dbCheck);

        if(queryExec(queryStr, &query))
        {
            qDebug() << "User created.";
            return true;
        }
        else
        {
            qDebug() << "User not created.";
            return false;
        }
    }
    else
    {
        qDebug() << "PostgreSQL connection error.";
        return false;
    }
}

bool DataBaseLMS::createDB()
{
    DataBaseSettings settings = getDataBaseSettings();
    QSqlDatabase dbCheck = QSqlDatabase::addDatabase("QPSQL");

    dbCheck.setUserName(UserNamePostgres);
    dbCheck.setPassword(PasswordPostgres);
    dbCheck.setHostName(settings.dbHostName);
    dbCheck.setPort(settings.dbPort);

    if (dbCheck.open())
    {
        //Создание БД
        QString queryStr = QString("CREATE DATABASE %1").arg(settings.dbName);
        QSqlQuery query = QSqlQuery(dbCheck);

        if(queryExec(queryStr, &query))
        {
            qDebug() << "The database has been created.";

            //Залитие БД
            if(prepareRestoreDBscript())
            {
                QProcess process;
                QString pgRestorePath = restoreDBscriptName;

                process.start("cmd /C " + pgRestorePath);
                process.waitForFinished(-1); // Ждать бесконечно, пока процесс не завершится
            }

            //Назначение владельца
            QString queryStr = QString("ALTER DATABASE %1 OWNER TO %2").arg(settings.dbName, settings.dbUserName);
            QSqlQuery query = QSqlQuery(dbCheck);
            if(queryExec(queryStr, &query))
            {
                qDebug() << "The owner of database has been changed.";
            }
            else
                return false;
        }
        else
        {
            qDebug() << "The database was not created..";
            return false;
        }
    }
    else
    {
        qDebug() << "PostgreSQL connection error.";
        return false;
    }

    dbCheck.close();

    QSqlDatabase dbCheck2 = QSqlDatabase::addDatabase("QPSQL");

    dbCheck2.setUserName(UserNamePostgres);
    dbCheck2.setPassword(PasswordPostgres);
    dbCheck2.setHostName(settings.dbHostName);
    dbCheck2.setPort(settings.dbPort);
    dbCheck2.setDatabaseName(settings.dbName);

    if (dbCheck2.open())
    {
        QString newOwner = settings.dbUserName;

        // Получаем список таблиц
        QSqlQuery query(dbCheck2);
        query.exec("SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public';");

        while (query.next())
        {
            QString tableName = query.value(0).toString();
            QString alterQueryStr = QString("ALTER TABLE %1 OWNER TO %2;").arg(tableName).arg(newOwner);
            QSqlQuery alterQuery(dbCheck2);

            //dbCheck2.exec(alterQueryStr);

            if(!queryExec(alterQueryStr, &alterQuery))
            {
                qDebug() << "Error changing owner for table " << tableName << ":" << dbCheck2.lastError().text();
                return false;
            }
        }
    }

    return true;
}

bool DataBaseLMS::prepareRestoreDBscript()
{
    DataBaseSettings settings = getDataBaseSettings();

    QFile file(restoreDBscriptName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QTextStream out(&file);
        out << "set CURRENT_DIR=%~dp0\n";
        out << "cd %CURRENT_DIR%\n";
        out << QString("set \"PGPASSWORD=%1\"\n").arg(PasswordPostgres);
        out << QString("pg_restore -U %1 -h %2 -p %3 -d %4 %5\n").arg(UserNamePostgres,
                                                                                      settings.dbHostName,
                                                                                      QString::number(settings.dbPort),
                                                                                      settings.dbName,
                                                                                      backupEmptyName);
        file.close();
        return true;
    }
    else
        return false;
}
