#include "sitesController.h"

#include <QFile>
#include <QHostInfo>
#include <QStandardPaths>

#include "systemController.h"
#include "core/networkUtilities.h"

SitesController::SitesController(const std::shared_ptr<Settings> &settings, const QSharedPointer<SitesModel> &sitesModel, QObject *parent)
    : QObject(parent), m_settings(settings), m_sitesModel(sitesModel)
{
}

void SitesController::addSite(QString hostname)
{
    if (hostname.isEmpty()) {
        return;
    }

    if (!hostname.contains(".")) {
        emit errorOccurred(tr("Hostname not look like ip adress or domain name"));
        return;
    }

    if (!NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
        // get domain name if it present
        hostname.replace("https://", "");
        hostname.replace("http://", "");
        hostname.replace("ftp://", "");

        hostname = hostname.split("/", Qt::SkipEmptyParts).first();
    }

    const auto &resolveCallback = [this](const QHostInfo &hostInfo) {
        const QList<QHostAddress> &addresses = hostInfo.addresses();
        for (const QHostAddress &addr : hostInfo.addresses()) {
            if (addr.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
                m_sitesModel->addSite(hostInfo.hostName(), addr.toString());
                break;
            }
        }
    };

    if (NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
        m_sitesModel->addSite(hostname, "");
    } else {
        m_sitesModel->addSite(hostname, "");
        QHostInfo::lookupHost(hostname, this, resolveCallback);
    }

    emit finished(tr("New site added: %1").arg(hostname));
}

void SitesController::removeSite(int index)
{
    auto modelIndex = m_sitesModel->index(index);
    auto hostname = m_sitesModel->data(modelIndex, SitesModel::Roles::UrlRole).toString();
    m_sitesModel->removeSite(modelIndex);

    emit finished(tr("Site removed: %1").arg(hostname));
}

void SitesController::removeSites()
{
    m_sitesModel->removeSites();

    emit finished(tr("Site list cleared!"));
}

void SitesController::importSites(const QString &fileName, bool replaceExisting)
{
    QByteArray jsonData;
    if (!SystemController::readFile(fileName, jsonData)) {
        emit errorOccurred(tr("Can't open file: %1").arg(fileName));
        return;
    }

    QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
    if (jsonDocument.isNull()) {
        emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
        return;
    }

    if (!jsonDocument.isArray()) {
        emit errorOccurred(tr("The JSON data is not an array in file: %1").arg(fileName));
        return;
    }

    auto jsonArray = jsonDocument.array();
    QMap<QString, QString> sites;
    QStringList ips;

    for (auto jsonValue : jsonArray) {
        auto jsonObject = jsonValue.toObject();
        auto hostname = jsonObject.value("hostname").toString("");
        auto ip = jsonObject.value("ip").toString("");

        if (!hostname.contains(".") && !NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
            qDebug() << hostname << " not look like ip adress or domain name";
            continue;
        }

        if (ip.isEmpty()) {
            ips.append(hostname);
        } else {
            ips.append(ip);
        }
        sites.insert(hostname, ip);
    }

    m_sitesModel->addSites(sites, replaceExisting);

    emit finished(tr("Import completed"));
}

void SitesController::exportSites(const QString &fileName)
{
    auto sites = m_sitesModel->getCurrentSites();

    QJsonArray jsonArray;

    for (const auto &site : sites) {
        QJsonObject jsonObject { { "hostname", site.first }, { "ip", site.second } };
        jsonArray.append(jsonObject);
    }

    QJsonDocument jsonDocument(jsonArray);
    QByteArray jsonData = jsonDocument.toJson();

    SystemController::saveFile(fileName, jsonData);

    emit finished(tr("Export completed"));
}
