#include <QSqlQuery>
#include "folderdao.h"
#include <QSqlError>
#include <QSqlError>
#include <optional>

bool FolderDao::insert(const Folder& folder)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "INSERT INTO Folder (accountId, name, parentFolderId, isInbox, isSent, isDrafts, isTrash, unreadCount, lastSynced) "
        "VALUES (:accountId, :name, :parentFolderId, :isInbox, :isSent, :isDrafts, :isTrash, :unreadCount, :lastSynced)"
    );
    query.bindValue(":accountId", folder.accountId());
    query.bindValue(":name", folder.name());
    query.bindValue(":parentFolderId", folder.parentFolderId());
    query.bindValue(":isInbox", folder.isInbox() ? 1 : 0);
    query.bindValue(":isSent", folder.isSent() ? 1 : 0);
    query.bindValue(":isDrafts", folder.isDrafts() ? 1 : 0);
    query.bindValue(":isTrash", folder.isTrash() ? 1 : 0);
    query.bindValue(":unreadCount", folder.unreadCount());
    query.bindValue(":lastSynced", folder.lastSynced());

    if (!query.exec()) {
        qWarning() << "Failed to insert folder:" << query.lastError().text();
        return false;
    }
    return true;
}

bool FolderDao::update(const Folder& folder)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "UPDATE Folder SET "
        "accountId = :accountId, "
        "name = :name, "
        "parentFolderId = :parentFolderId, "
        "isInbox = :isInbox, "
        "isSent = :isSent, "
        "isDrafts = :isDrafts, "
        "isTrash = :isTrash, "
        "unreadCount = :unreadCount, "
        "lastSynced = :lastSynced "
        "WHERE id = :id"
    );
    query.bindValue(":id", folder.id());
    query.bindValue(":accountId", folder.accountId());
    query.bindValue(":name", folder.name());
    query.bindValue(":parentFolderId", folder.parentFolderId());
    query.bindValue(":isInbox", folder.isInbox() ? 1 : 0);
    query.bindValue(":isSent", folder.isSent() ? 1 : 0);
    query.bindValue(":isDrafts", folder.isDrafts() ? 1 : 0);
    query.bindValue(":isTrash", folder.isTrash() ? 1 : 0);
    query.bindValue(":unreadCount", folder.unreadCount());
    query.bindValue(":lastSynced", folder.lastSynced());

    if (!query.exec()) {
        qWarning() << "Failed to update folder:" << query.lastError().text();
        return false;
    }
    return true;
}

bool FolderDao::remove(int id)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("DELETE FROM Folder WHERE id = :id");
    query.bindValue(":id", id);

    if (!query.exec()) {
        qWarning() << "Failed to delete folder:" << query.lastError().text();
        return false;
    }
    return true;
}

std::optional<Folder> FolderDao::findById(int id)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, accountId, name, parentFolderId, isInbox, isSent, isDrafts, isTrash, unreadCount, lastSynced FROM Folder WHERE id = :id");
    query.bindValue(":id", id);

    if (!query.exec()) {
        qWarning() << "Failed to find folder by id:" << query.lastError().text();
        return std::nullopt;
    }

    if (query.next()) {
        Folder fld;
        fld.setId(query.value(0).toInt());
        fld.setAccountId(query.value(1).toInt());
        fld.setName(query.value(2).toString());
        fld.setParentFolderId(query.value(3).toString());
        fld.setInbox(query.value(4).toBool());
        fld.setSent(query.value(5).toBool());
        fld.setDrafts(query.value(6).toBool());
        fld.setTrash(query.value(7).toBool());
        fld.setUnreadCount(query.value(8).toInt());
        fld.setLastSynced(query.value(9).toDateTime());
        return fld;
    }
    return std::nullopt;
}

QVector<Folder> FolderDao::findAll()
{
    QVector<Folder> folders;
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    if (!query.exec("SELECT id, accountId, name, parentFolderId, isInbox, isSent, isDrafts, isTrash, unreadCount, lastSynced FROM Folder")) {
        qWarning() << "Failed to fetch all folders:" << query.lastError().text();
        return folders;
    }

    while (query.next()) {
        Folder fld;
        fld.setId(query.value(0).toInt());
        fld.setAccountId(query.value(1).toInt());
        fld.setName(query.value(2).toString());
        fld.setParentFolderId(query.value(3).toString());
        fld.setInbox(query.value(4).toBool());
        fld.setSent(query.value(5).toBool());
        fld.setDrafts(query.value(6).toBool());
        fld.setTrash(query.value(7).toBool());
        fld.setUnreadCount(query.value(8).toInt());
        fld.setLastSynced(query.value(9).toDateTime());
        folders.append(fld);
    }
    return folders;
}

QVector<Folder> FolderDao::findByAccountId(int accountId)
{
    QVector<Folder> folders;
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, accountId, name, parentFolderId, isInbox, isSent, isDrafts, isTrash, unreadCount, lastSynced FROM Folder WHERE accountId = :accountId");
    query.bindValue(":accountId", accountId);

    if (!query.exec()) {
        qWarning() << "Failed to fetch folders by account id:" << query.lastError().text();
        return folders;
    }

    while (query.next()) {
        Folder fld;
        fld.setId(query.value(0).toInt());
        fld.setAccountId(query.value(1).toInt());
        fld.setName(query.value(2).toString());
        fld.setParentFolderId(query.value(3).toString());
        fld.setInbox(query.value(4).toBool());
        fld.setSent(query.value(5).toBool());
        fld.setDrafts(query.value(6).toBool());
        fld.setTrash(query.value(7).toBool());
        fld.setUnreadCount(query.value(8).toInt());
        fld.setLastSynced(query.value(9).toDateTime());
        folders.append(fld);
    }
    return folders;
}