#include "imapsynchronizer.h"
#include <QDebug>
#include <cstdlib>
#include <QTextStream>
#include <QRegularExpression>
#include <QEventLoop>
#include <QTimer>
#include <QSqlQuery>
#include <QSqlError>
#include "db/dao/folderdao.h"
#include "core/mailitem.h"
#include "db/dao/mailitemdao.h"
#include "db/databasemanager.h"

ImapSynchronizer::ImapSynchronizer(QObject* parent)
    : Synchronizer(parent)
{
}

bool ImapSynchronizer::initialize(const Account& account)
{
    // Store the account for later use (e.g., for syncFolder)
    m_account = account;
    // Store connection settings for later use
    const Account::ConnectionSettings& settings = account.connectionSettings();
    m_host = settings.incomingHost;
    m_port = settings.incomingPort;
    m_useSsl = settings.incomingSsl;
    m_username = settings.username;
    m_password = settings.password;
    m_authMethod = settings.authMethod;
    qDebug() << "IMAP Synchronizer initialize:"
             << "host:" << m_host
             << "port:" << m_port
             << "ssl:" << m_useSsl
             << "username:" << m_username;
    emit statusMessage(QStringLiteral("Initializing IMAP synchronizer..."));
    emit progressChanged(0);
    emit progressChanged(100);
    return true;
}

QString ImapSynchronizer::generateEventId() const
{
    // Simple implementation using timestamp and random component
    return QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" +
           QString::number(std::rand());
}

bool ImapSynchronizer::sendCommand(QSslSocket& socket, const QString& command, QString& response) const
{
    QByteArray cmd = command.toUtf8() + "\r\n";
    qint64 bytesWritten = socket.write(cmd);
    if (bytesWritten == -1) {
        qWarning() << "Failed to write to socket:" << socket.errorString();
        return false;
    }
    if (!socket.waitForBytesWritten(3000)) {
        qWarning() << "Timeout waiting for bytes written:" << socket.errorString();
        return false;
    }
    // We'll read response in caller using waitForResponse
    return true;
}

bool ImapSynchronizer::waitForResponse(QSslSocket& socket, const QString& expectedTag, QString& response) const
{
    response.clear();
    while (true) {
        if (!socket.waitForReadyRead(10000)) {
            qWarning() << "Timeout waiting for response:" << socket.errorString();
            return false;
        }
        while (socket.canReadLine()) {
            QByteArray line = socket.readLine();
            QString lineStr = QString::fromUtf8(line).trimmed();
            response += lineStr + "\n";
            // Check if this line is the completion response for our command
            if (lineStr.startsWith(expectedTag + " ") || lineStr.startsWith("*")) {
                // Continue reading until we see the tagged completion
                if (lineStr.startsWith(expectedTag + " OK") ||
                    lineStr.startsWith(expectedTag + " NO") ||
                    lineStr.startsWith(expectedTag + " BAD")) {
                    return true;
                }
            }
        }
    }
}

QVector<Folder> ImapSynchronizer::parseListResponse(const QString& response) const
{
    QVector<Folder> folders;
    QRegularExpression re(R"(\* LIST\s*\(([^)]*)\)\s+\"([^"]*)\"\s+\"(.*)\"\r?\n)");
    // Example: * LIST (\HasNoChildren) "." "INBOX"
    // Also handle NIL delimiter: "" "" "INBOX"
    QRegularExpressionMatchIterator it = re.globalMatch(response);
    while (it.hasNext()) {
        QRegularExpressionMatch match = it.next();
        QString flagsStr = match.captured(1); // e.g. \HasNoChildren
        QString delimiter = match.captured(2); // usually "." or "/"
        QString mailbox = match.captured(3); // the mailbox name, possibly quoted
        Folder folder;
        folder.setName(mailbox);
        // Set special flags based on name or attributes
        QString nameLower = mailbox.toLower();
        if (nameLower == "inbox") {
            folder.setInbox(true);
        } else if (nameLower == "sent" || nameLower == "sent messages") {
            folder.setSent(true);
        } else if (nameLower == "drafts" || nameLower == "draft") {
            folder.setDrafts(true);
        } else if (nameLower == "trash" || nameLower == "deleted messages") {
            folder.setTrash(true);
        } else if (nameLower == "spam" || nameLower == "junk") {
            // no specific flag, but we could add a custom attribute; we'll just leave as normal
        }
        // Parse flags for special-use attributes (RFC 6154)
        if (flagsStr.contains("\\Drafts", Qt::CaseInsensitive))
            folder.setDrafts(true);
        if (flagsStr.contains("\\Sent", Qt::CaseInsensitive))
            folder.setSent(true);
        if (flagsStr.contains("\\Trad", Qt::CaseInsensitive)) // Note: likely a typo in original, we keep as is
            folder.setTrash(true);
        folders.append(folder);
    }
    return folders;
}

QVector<Folder> ImapSynchronizer::getFolders() const
{
    QVector<Folder> folders;
    QSslSocket socket;
    // Connect
    qDebug() << "IMAP getFolders: connecting to host" << m_host << "port:" << m_port << "ssl:" << m_useSsl;
    if (m_useSsl) {
        socket.connectToHostEncrypted(m_host, m_port);
    } else {
        socket.connectToHost(m_host, m_port);
    }
    if (!socket.waitForConnected(5000)) {
        qWarning() << "Failed to connect to IMAP server:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to connect to IMAP server: %1").arg(socket.errorString()));
        return folders;
    }
    qDebug() << "IMAP getFolders: connected";
    if (m_useSsl && !socket.waitForEncrypted(5000)) {
        qWarning() << "TLS handshake failed:" << socket.errorString();
        emit statusMessage(QStringLiteral("TLS handshake failed: %1").arg(socket.errorString()));
        return folders;
    }
    qDebug() << "IMAP getFolders: TLS handshake done (if SSL)";
    // Read initial greeting (optional)
    if (!socket.waitForReadyRead(5000)) {
        qWarning() << "No greeting from IMAP server";
        emit statusMessage(QStringLiteral("No greeting from IMAP server"));
        socket.disconnectFromHost();
        return folders;
    }
    qDebug() << "IMAP getFolders: got initial greeting";
    while (socket.canReadLine())
        socket.readLine(); // discard greeting lines
    qDebug() << "IMAP getFolders: discarded greeting lines";

    // Login
    QString loginCmd = QStringLiteral("a001 LOGIN %1 %2").arg(m_username, m_password);
    QString resp;
    if (!sendCommand(socket, loginCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a001"), resp) ||
        !resp.contains(QStringLiteral("a001 OK"))) {
        qWarning() << "LOGIN failed:" << resp;
        emit statusMessage(QStringLiteral("LOGIN failed: %1").arg(resp));
        socket.disconnectFromHost();
        return folders;
    }
    qDebug() << "IMAP getFolders: LOGIN succeeded";

    // List folders
    QString listCmd = QStringLiteral("a002 LIST \"\" \"*\"");
    resp.clear();
    if (!sendCommand(socket, listCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a002"), resp) ||
        !resp.contains(QStringLiteral("a002 OK"))) {
        qWarning() << "LIST failed:" << resp;
        emit statusMessage(QStringLiteral("LIST failed: %1").arg(resp));
        socket.disconnectFromHost();
        return folders;
    }
    qDebug() << "IMAP getFolders: LIST command succeeded, response length:" << resp.length();

    // Parse the response
    folders = parseListResponse(resp);
    qDebug() << "IMAP getFolders: parsed" << folders.size() << "folders";

    // Logout
    QString logoutCmd = QStringLiteral("a003 LOGOUT");
    sendCommand(socket, logoutCmd, resp);
    waitForResponse(socket, QStringLiteral("a003"), resp);
    socket.disconnectFromHost();
    qDebug() << "IMAP getFolders: returning" << folders.size() << "folders";
    return folders;
}

bool ImapSynchronizer::syncFolder(const Folder& folder)
{
    emit statusMessage(QStringLiteral("Syncing folder: %1").arg(folder.name()));
    emit progressChanged(0);
    QSslSocket socket;
    // Connect
    if (m_useSsl) {
        socket.connectToHostEncrypted(m_host, m_port);
    } else {
        socket.connectToHost(m_host, m_port);
    }
    if (!socket.waitForConnected(5000)) {
        qWarning() << "Failed to connect to IMAP server:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to connect to IMAP server: %1").arg(socket.errorString()));
        return false;
    }
    if (m_useSsl && !socket.waitForEncrypted(5000)) {
        qWarning() << "TLS handshake failed:" << socket.errorString();
        emit statusMessage(QStringLiteral("TLS handshake failed: %1").arg(socket.errorString()));
        return false;
    }
    // Read initial greeting (optional)
    if (!socket.waitForReadyRead(5000)) {
        qWarning() << "No greeting from IMAP server";
        emit statusMessage(QStringLiteral("No greeting from IMAP server"));
        socket.disconnectFromHost();
        return false;
    }
    while (socket.canReadLine())
        socket.readLine(); // discard greeting lines

    // Login
    QString loginCmd = QStringLiteral("a001 LOGIN %1 %2").arg(m_username, m_password);
    QString resp;
    if (!sendCommand(socket, loginCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a001"), resp) ||
        !resp.contains(QStringLiteral("a001 OK"))) {
        qWarning() << "LOGIN failed:" << resp;
        emit statusMessage(QStringLiteral("LOGIN failed: %1").arg(resp));
        socket.disconnectFromHost();
        return false;
    }
    emit progressChanged(20);

    // Select folder
    QString selectCmd = QStringLiteral("a002 SELECT \"%1\"").arg(folder.name());
    resp.clear();
    if (!sendCommand(socket, selectCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a002"), resp) ||
        !resp.contains(QStringLiteral("a002 OK"))) {
        qWarning() << "SELECT failed:" << resp;
        emit statusMessage(QStringLiteral("SELECT failed: %1").arg(resp));
        socket.disconnectFromHost();
        return false;
    }
    emit progressChanged(40);

    // Get all UIDs in the mailbox
    QString searchCmd = QStringLiteral("a003 UID SEARCH ALL");
    resp.clear();
    if (!sendCommand(socket, searchCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a003"), resp) ||
        !resp.contains(QStringLiteral("a003 OK"))) {
        qWarning() << "SEARCH failed:" << resp;
        emit statusMessage(QStringLiteral("SEARCH failed: %1").arg(resp));
        socket.disconnectFromHost();
        return false;
    }
    // Extract UIDs from response (lines containing numbers before the tagged OK)
    QList<qint64> uidList;
    QStringList lines = resp.split('\n', Qt::SkipEmptyParts);
    for (const QString& line : lines) {
        if (line.startsWith(QLatin1Char('*')) && line.contains(QStringLiteral("SEARCH"))) {
            // Example: * SEARCH 1 2 3 4 5
            QStringList parts = line.split(QRegularExpression("\\s+"));
            for (int i = 2; i < parts.size(); ++i) { // skip "* SEARCH"
                bool ok2;
                qint64 uid = parts[i].toLongLong(&ok2);
                if (ok2)
                    uidList.append(uid);
            }
        }
    }
    if (uidList.isEmpty()) {
        qDebug() << "No messages in folder" << folder.name();
        // Still need to update unread count to 0
        std::optional<Folder> fOpt = FolderDao::findById(folder.id());
        if (fOpt) {
            Folder f = *fOpt;
            f.setUnreadCount(0);
            FolderDao::update(f);
        }
        // Logout
        QString logoutCmd = QStringLiteral("a004 LOGOUT");
        sendCommand(socket, logoutCmd, resp);
        waitForResponse(socket, QStringLiteral("a004"), resp);
        socket.disconnectFromHost();
        emit progressChanged(100);
        return true;
    }
    emit progressChanged(50);

    // Fetch FLAGS for all UIDs (we could batch fetch, but do one by one for simplicity)
    QMap<qint64, QPair<bool, bool>> flagsMap; // uid -> (seen, flagged)
    for (qint64 uid : uidList) {
        QString fetchCmd = QStringLiteral("a%1 UID FETCH %2 (FLAGS)").arg(QString::number(uid * 10, 16)).arg(uid);
        resp.clear();
        if (!sendCommand(socket, fetchCmd, resp) ||
            !waitForResponse(socket, QStringLiteral("a%1").arg(uid * 10, 16), resp)) {
            qWarning() << "FETCH FLAGS failed for uid" << uid;
            continue;
        }
        bool seen = resp.contains("\\Seen");
        bool flagged = resp.contains("\\Flagged");
        flagsMap[uid] = qMakePair(seen, flagged);
    }
    emit progressChanged(70);

    // Load all mail items for this folder from local DB
    QVector<MailItem> localItems = MailItemDao::findByFolderId(folder.id());
    QMap<qint64, MailItem> uidToItem;
    for (MailItem& item : localItems) {
        uidToItem[item.uid()] = item;
    }

    // Update local items with flags from server
    QList<MailItem> toUpdate;
    for (auto it = uidToItem.begin(); it != uidToItem.end(); ++it) {
        qint64 uid = it.key();
        MailItem& item = it.value();
        if (flagsMap.contains(uid)) {
            bool seen = flagsMap[uid].first;
            bool flagged = flagsMap[uid].second;
            bool changed = false;
            if (item.isRead() != seen) {
                item.setRead(seen);
                changed = true;
            }
            if (item.isFlagged() != flagged) {
                item.setFlagged(flagged);
                changed = true;
            }
            if (changed) {
                toUpdate.append(item);
            }
        }
        // If uid not found on server anymore, we could optionally delete locally, but we keep.
    }

    // Persist changes
    for (MailItem& item : toUpdate) {
        if (!MailItemDao::update(item)) {
            qWarning() << "Failed to update mail item uid" << item.uid();
        }
    }

    // Compute unread count from local items (or we could count unseen from server)
    int unreadCount = 0;
    for (const MailItem& item : localItems) {
        if (!item.isRead())
            ++unreadCount;
    }
    // Update folder unread count
    std::optional<Folder> fOpt = FolderDao::findById(folder.id());
    if (fOpt) {
        Folder f = *fOpt;
        f.setUnreadCount(unreadCount);
        if (!FolderDao::update(f)) {
            qWarning() << "Failed to update folder unread count for folderId" << folder.id();
        }
    }

    // Logout
    QString logoutCmd = QStringLiteral("a004 LOGOUT");
    sendCommand(socket, logoutCmd, resp);
    waitForResponse(socket, QStringLiteral("a004"), resp);
    socket.disconnectFromHost();
    emit progressChanged(100);
    return !toUpdate.isEmpty(); // return true if we made changes
}

QVector<MailItem> ImapSynchronizer::fetchMailItems(const QString& folderId, qint64 sinceUid)
{
    QVector<MailItem> items;
    qDebug() << "IMAP fetchMailItems called for folderId:" << folderId << "sinceUid:" << sinceUid;
    // Get folder object
    bool ok;
    int fid = folderId.toInt(&ok);
    if (!ok) {
        qWarning() << "Invalid folderId:" << folderId;
        return items;
    }
    std::optional<Folder> fOpt = FolderDao::findById(fid);
    if (!fOpt) {
        qWarning() << "Folder not found for id:" << fid;
        return items;
    }
    const Folder& folder = *fOpt;

    emit statusMessage(QStringLiteral("Fetching emails from folder: %1").arg(folder.name()));
    emit progressChanged(0);

    QSslSocket socket;
    // Connect
    if (m_useSsl) {
        socket.connectToHostEncrypted(m_host, m_port);
    } else {
        socket.connectToHost(m_host, m_port);
    }
    if (!socket.waitForConnected(5000)) {
        qWarning() << "Failed to connect to IMAP server:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to connect to IMAP server: %1").arg(socket.errorString()));
        return items;
    }
    if (m_useSsl && !socket.waitForEncrypted(5000)) {
        qWarning() << "TLS handshake failed:" << socket.errorString();
        emit statusMessage(QStringLiteral("TLS handshake failed: %1").arg(socket.errorString()));
        return items;
    }
    // Read initial greeting (optional)
    if (!socket.waitForReadyRead(5000)) {
        qWarning() << "No greeting from IMAP server";
        emit statusMessage(QStringLiteral("No greeting from IMAP server"));
        socket.disconnectFromHost();
        return items;
    }
    while (socket.canReadLine())
        socket.readLine(); // discard greeting lines

    // Login
    QString loginCmd = QStringLiteral("a001 LOGIN %1 %2").arg(m_username, m_password);
    QString resp;
    if (!sendCommand(socket, loginCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a001"), resp) ||
        !resp.contains(QStringLiteral("a001 OK"))) {
        qWarning() << "LOGIN failed:" << resp;
        emit statusMessage(QStringLiteral("LOGIN failed: %1").arg(resp));
        socket.disconnectFromHost();
        return items;
    }
    emit progressChanged(10);

    // Select folder
    QString selectCmd = QStringLiteral("a002 SELECT \"%1\"").arg(folder.name());
    resp.clear();
    if (!sendCommand(socket, selectCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a002"), resp) ||
        !resp.contains(QStringLiteral("a002 OK"))) {
        qWarning() << "SELECT failed:" << resp;
        emit statusMessage(QStringLiteral("SELECT failed: %1").arg(resp));
        socket.disconnectFromHost();
        return items;
    }
    emit progressChanged(20);

    // Determine search criteria
    QString searchCmd;
    if (sinceUid > 0) {
        searchCmd = QStringLiteral("a003 UID SEARCH %1:*").arg(sinceUid);
    } else {
        searchCmd = QStringLiteral("a003 UID SEARCH ALL");
    }
    resp.clear();
    if (!sendCommand(socket, searchCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a003"), resp) ||
        !resp.contains(QStringLiteral("a003 OK"))) {
        qWarning() << "SEARCH failed:" << resp;
        emit statusMessage(QStringLiteral("SEARCH failed: %1").arg(resp));
        socket.disconnectFromHost();
        return items;
    }
    // Extract UIDs from response (lines containing numbers before the tagged OK)
    QList<qint64> uidList;
    QStringList lines = resp.split('\n', Qt::SkipEmptyParts);
    for (const QString& line : lines) {
        if (line.startsWith(QLatin1Char('*')) && line.contains(QStringLiteral("SEARCH"))) {
            // Example: * SEARCH 1 2 3 4 5
            QStringList parts;
            parts = line.split(QRegularExpression("\\s+"));
            for (int i = 2; i < parts.size(); ++i) { // skip "* SEARCH"
                bool ok2;
                qint64 uid = parts[i].toLongLong(&ok2);
                if (ok2)
                    uidList.append(uid);
            }
        }
    }
    if (uidList.isEmpty()) {
        qDebug() << "No new messages to fetch";
        emit statusMessage(QStringLiteral("No new messages to fetch"));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return items;
    }
    emit progressChanged(30);

    // Fetch each UID
    int total = uidList.size();
    for (int i = 0; i < uidList.size(); ++i) {
        qint64 uid = uidList[i];
        // Fetch envelope, flags, internal date
        QString fetchCmd = QStringLiteral("a%1 UID FETCH %2 (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)")
                               .arg(QString::number(uid * 10, 16)).arg(uid);
        resp.clear();
        if (!sendCommand(socket, fetchCmd, resp) ||
            !waitForResponse(socket, QStringLiteral("a%1").arg(uid * 10, 16), resp)) {
            qWarning() << "FETCH failed for uid" << uid;
            continue;
        }
        // Parse response
        bool seen = false, flagged = false;
        QDateTime internalDate;
        QString subject, from;
        // Look for FLAGS
        if (resp.contains("\\Seen"))
            seen = true;
        if (resp.contains("\\Flagged"))
            flagged = true;
        // InternalDate
        QRegularExpression internalRegex(QStringLiteral("INTERNALDATE \"([^\"]*)\""));
        QRegularExpressionMatch internalMatch = internalRegex.match(resp);
        if (internalMatch.hasMatch()) {
            QString dateStr = internalMatch.captured(1);
            // IMAP internal-date format: "dd-Mmm-yyyy hh:mm:ss zzz"
            internalDate = QDateTime::fromString(dateStr, "dd-MMM-yyyy hh:mm:ss");
            if (!internalDate.isValid())
                internalDate = QDateTime::currentDateTimeUtc(); // fallback
        } else {
            internalDate = QDateTime::currentDateTimeUtc();
        }
        // Envelope: extract subject and from (simplified)
        QRegularExpression envelopeRegex(QStringLiteral("ENVELOPE \\((.*)\\)"));
        QRegularExpressionMatch envelopeMatch = envelopeRegex.match(resp);
        if (envelopeMatch.hasMatch()) {
            QString envelopeStr = envelopeMatch.captured(1);
            // Envelope fields: date subject from sender reply-to to cc bcc in-reply-to message-id
            // We'll parse by splitting on spaces but respecting quoted strings - simplified:
            int idx = 0;
            // date
            int d1 = envelopeStr.indexOf('\"', idx);
            if (d1 != -1) {
                int d2 = envelopeStr.indexOf('\"', d1 + 1);
                if (d2 != -1) {
                    idx = d2 + 1;
                    // subject
                    int s1 = envelopeStr.indexOf('\"', idx);
                    if (s1 != -1) {
                        int s2 = envelopeStr.indexOf('\"', s1 + 1);
                        if (s2 != -1) {
                            subject = envelopeStr.mid(s1 + 1, s2 - s1 - 1);
                        }
                    }
                }
            }
        }
        // If subject empty, set placeholder
        if (subject.isEmpty())
            subject = QStringLiteral("(No Subject)");
        // From extraction: we'll just parse the from field similarly (third quoted string)
        // For simplicity, we'll set a placeholder; we could improve but skip for now.
        if (from.isEmpty())
            from = QStringLiteral("unknown@example.com");

        MailItem item;
        item.setFolderId(folder.id());
        item.setSubject(subject);
        item.setSender(from);
        // For simplicity, set recipient as empty
        item.setRecipient(QString());
        item.setDate(internalDate);
        item.setRead(seen);
        item.setFlagged(flagged);
        item.setUid(uid); // store the IMAP UID
        // Size unknown; we could parse RFC822.SIZE but skip
        // Insert into DB
        if (MailItemDao::insert(item)) {
            QSqlQuery qry;
            qry.exec(QStringLiteral("SELECT last_insert_rowid()"));
            qint64 newId = -1;
            if (qry.next())
                newId = qry.value(0).toLongLong();
            item.setId(newId);
            items.append(item);
            qDebug() << "Fetched and stored uid" << uid << "as mail id" << newId;
        } else {
            qWarning() << "Failed to insert mail item for uid" << uid;
        }
        // Update progress
        int prog = 30 + ((i + 1) * 70) / total;
        emit progressChanged(prog);
    }

    // Logout
    QString logoutCmd = QStringLiteral("a004 LOGOUT");
    sendCommand(socket, logoutCmd, resp);
    waitForResponse(socket, QStringLiteral("a004"), resp);
    socket.disconnectFromHost();
    emit statusMessage(QStringLiteral("Fetched %1 new email(s)").arg(items.size()));
    emit progressChanged(100);
    qDebug() << "IMAP fetchMailItems returning" << items.size() << "items";
    return items;
}

bool ImapSynchronizer::appendMailItem(const QString& folderId, const MailItem& item)
{
    emit statusMessage(QStringLiteral("Appending email to folder: %1").arg(folderId));
    emit progressChanged(0);
    bool ok;
    int fid = folderId.toInt(&ok);
    if (!ok) {
        qWarning() << "Invalid folderId:" << folderId;
        emit statusMessage(QStringLiteral("Invalid folder ID"));
        emit progressChanged(100);
        return false;
    }
    std::optional<Folder> fOpt = FolderDao::findById(fid);
    if (!fOpt) {
        qWarning() << "Folder not found for id:" << fid;
        emit statusMessage(QStringLiteral("Folder not found"));
        emit progressChanged(100);
        return false;
    }
    const Folder& folder = *fOpt;

    // Build RFC822 message
    QString dateStr = item.date().toString(Qt::RFC2822Date);
    QString from = item.sender();
    QString to = item.recipient();
    QString cc = item.cc();
    QString bcc = item.bcc();
    QString subject = item.subject();
    QString body = item.bodyHtml(); // assuming bodyHtml contains the body text

    QStringList headers;
    if (!dateStr.isEmpty()) headers << QString("Date: %1").arg(dateStr);
    if (!from.isEmpty()) headers << QString("From: %1").arg(from);
    if (!to.isEmpty()) headers << QString("To: %1").arg(to);
    if (!cc.isEmpty()) headers << QString("Cc: %1").arg(cc);
    if (!bcc.isEmpty()) headers << QString("Bcc: %1").arg(bcc);
    if (!subject.isEmpty()) headers << QString("Subject: %1").arg(subject);
    headers << QStringLiteral("MIME-Version: 1.0");
    headers << QStringLiteral("Content-Type: text/plain; charset=\"utf-8\"");
    headers << QStringLiteral("Content-Transfer-Encoding: 7bit");
    headers << QStringLiteral(""); // empty line before body
    if (!body.isEmpty()) headers << body;

    QString message = headers.join(QStringLiteral("\r\n"));
    QByteArray messageBytes = message.toUtf8();

    QSslSocket socket;
    if (m_useSsl) socket.connectToHostEncrypted(m_host, m_port);
    else socket.connectToHost(m_host, m_port);
    if (!socket.waitForConnected(5000)) {
        qWarning() << "Failed to connect to IMAP server:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to connect to IMAP server: %1").arg(socket.errorString()));
        emit progressChanged(100);
        return false;
    }
    if (m_useSsl && !socket.waitForEncrypted(5000)) {
        qWarning() << "TLS handshake failed:" << socket.errorString();
        emit statusMessage(QStringLiteral("TLS handshake failed: %1").arg(socket.errorString()));
        emit progressChanged(100);
        return false;
    }
    if (!socket.waitForReadyRead(5000)) {
        qWarning() << "No greeting from IMAP server";
        emit statusMessage(QStringLiteral("No greeting from IMAP server"));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    while (socket.canReadLine())
        socket.readLine(); // discard greeting lines

    // Login
    QString loginCmd = QStringLiteral("a001 LOGIN %1 %2").arg(m_username, m_password);
    QString resp;
    if (!sendCommand(socket, loginCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a001"), resp) ||
        !resp.contains(QStringLiteral("a001 OK"))) {
        qWarning() << "LOGIN failed:" << resp;
        emit statusMessage(QStringLiteral("LOGIN failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(30);

    // APPEND
    QString appendCmd = QStringLiteral("a002 APPEND \"%1\" (\\Seen) {%2}\r\n").arg(folder.name()).arg(messageBytes.size());
    QByteArray cmd = appendCmd.toUtf8() + messageBytes + "\r\n";
    qint64 bytesWritten = socket.write(cmd);
    if (bytesWritten == -1) {
        qWarning() << "Failed to write APPEND command:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to write APPEND command: %1").arg(socket.errorString()));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    if (!socket.waitForBytesWritten(3000)) {
        qWarning() << "Timeout waiting for bytes written:" << socket.errorString();
        emit statusMessage(QStringLiteral("Timeout waiting for bytes written: %1").arg(socket.errorString()));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    resp.clear();
    if (!waitForResponse(socket, QStringLiteral("a002"), resp) ||
        !resp.contains(QStringLiteral("a002 OK"))) {
        qWarning() << "APPEND failed:" << resp;
        emit statusMessage(QStringLiteral("APPEND failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(80);

    // Logout
    QString logoutCmd = QStringLiteral("a003 LOGOUT");
    sendCommand(socket, logoutCmd, resp);
    waitForResponse(socket, QStringLiteral("a003"), resp);
    socket.disconnectFromHost();
    emit statusMessage(QStringLiteral("Email appended successfully"));
    emit progressChanged(100);
    return true;
}

bool ImapSynchronizer::updateMailItemFlags(const QString& folderId,
                                           const QString& itemUid,
                                           bool read, bool flagged)
{
    emit statusMessage(QStringLiteral("Updating email flags"));
    emit progressChanged(0);
    bool ok;
    qint64 uid = itemUid.toLongLong(&ok);
    if (!ok) {
        qWarning() << "Invalid itemUid:" << itemUid;
        emit statusMessage(QStringLiteral("Invalid item UID"));
        emit progressChanged(100);
        return false;
    }
    std::optional<MailItem> opt = MailItemDao::findById(uid);
    if (!opt) {
        qWarning() << "MailItem not found for uid:" << uid;
        emit statusMessage(QStringLiteral("MailItem not found"));
        emit progressChanged(100);
        return false;
    }
    const MailItem& mail = *opt;
    std::optional<Folder> fOpt = FolderDao::findById(mail.folderId());
    if (!fOpt) {
        qWarning() << "Folder not found for mail item uid:" << uid;
        emit statusMessage(QStringLiteral("Folder not found"));
        emit progressChanged(100);
        return false;
    }
    const Folder& folder = *fOpt;

    QSslSocket socket;
    if (m_useSsl) socket.connectToHostEncrypted(m_host, m_port);
    else socket.connectToHost(m_host, m_port);
    if (!socket.waitForConnected(5000)) {
        qWarning() << "Failed to connect to IMAP server:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to connect to IMAP server: %1").arg(socket.errorString()));
        emit progressChanged(100);
        return false;
    }
    if (m_useSsl && !socket.waitForEncrypted(5000)) {
        qWarning() << "TLS handshake failed:" << socket.errorString();
        emit statusMessage(QStringLiteral("TLS handshake failed: %1").arg(socket.errorString()));
        emit progressChanged(100);
        return false;
    }
    if (!socket.waitForReadyRead(5000)) {
        qWarning() << "No greeting from IMAP server";
        emit statusMessage(QStringLiteral("No greeting from IMAP server"));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    while (socket.canReadLine())
        socket.readLine(); // discard greeting lines

    // Login
    QString loginCmd = QStringLiteral("a001 LOGIN %1 %2").arg(m_username, m_password);
    QString resp;
    if (!sendCommand(socket, loginCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a001"), resp) ||
        !resp.contains(QStringLiteral("a001 OK"))) {
        qWarning() << "LOGIN failed:" << resp;
        emit statusMessage(QStringLiteral("LOGIN failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(20);

    // Select folder
    QString selectCmd = QStringLiteral("a002 SELECT \"%1\"").arg(folder.name());
    resp.clear();
    if (!sendCommand(socket, selectCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a002"), resp) ||
        !resp.contains(QStringLiteral("a002 OK"))) {
        qWarning() << "SELECT failed:" << resp;
        emit statusMessage(QStringLiteral("SELECT failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(40);

    bool allOk = true;
    if (read != mail.isRead()) {
        QString storeCmd = QStringLiteral("a003 UID STORE %1 %2\\Seen")
                               .arg(uid)
                               .arg(read ? "+" : "-");
        resp.clear();
        if (!sendCommand(socket, storeCmd, resp) ||
            !waitForResponse(socket, QStringLiteral("a003"), resp) ||
            !resp.contains(QStringLiteral("a003 OK"))) {
            qWarning() << "STORE Seen failed:" << resp;
            emit statusMessage(QStringLiteral("STORE Seen failed: %1").arg(resp));
            allOk = false;
        }
    }
    if (flagged != mail.isFlagged()) {
        QString storeCmd = QStringLiteral("a004 UID STORE %1 %2\\Flagged")
                               .arg(uid)
                               .arg(flagged ? "+" : "-");
        resp.clear();
        if (!sendCommand(socket, storeCmd, resp) ||
            !waitForResponse(socket, QStringLiteral("a004"), resp) ||
            !resp.contains(QStringLiteral("a004 OK"))) {
            qWarning() << "STORE Flagged failed:" << resp;
            emit statusMessage(QStringLiteral("STORE Flagged failed: %1").arg(resp));
            allOk = false;
        }
    }
    emit progressChanged(80);

    // Logout
    QString logoutCmd = QStringLiteral("a005 LOGOUT");
    sendCommand(socket, logoutCmd, resp);
    waitForResponse(socket, QStringLiteral("a005"), resp);
    socket.disconnectFromHost();
    if (allOk) {
        // Update local copy
        MailItem updated = mail;
        updated.setRead(read);
        updated.setFlagged(flagged);
        if (MailItemDao::update(updated)) {
            emit statusMessage(QStringLiteral("Email flags updated successfully"));
            emit progressChanged(100);
            return true;
        }
    }
    emit statusMessage(QStringLiteral("Failed to update email flags"));
    emit progressChanged(100);
    return false;
}

bool ImapSynchronizer::deleteMailItem(const QString& folderId,
                                      const QString& itemUid)
{
    emit statusMessage(QStringLiteral("Deleting email"));
    emit progressChanged(0);
    bool ok;
    qint64 uid = itemUid.toLongLong(&ok);
    if (!ok) {
        qWarning() << "Invalid itemUid:" << itemUid;
        emit statusMessage(QStringLiteral("Invalid item UID"));
        emit progressChanged(100);
        return false;
    }
    std::optional<MailItem> opt = MailItemDao::findById(uid);
    if (!opt) {
        qWarning() << "MailItem not found for uid:" << uid;
        emit statusMessage(QStringLiteral("MailItem not found"));
        emit progressChanged(100);
        return false;
    }
    const MailItem& mail = *opt;
    std::optional<Folder> fOpt = FolderDao::findById(mail.folderId());
    if (!fOpt) {
        qWarning() << "Folder not found for mail item uid:" << uid;
        emit statusMessage(QStringLiteral("Folder not found"));
        emit progressChanged(100);
        return false;
    }
    const Folder& folder = *fOpt;

    QSslSocket socket;
    if (m_useSsl) socket.connectToHostEncrypted(m_host, m_port);
    else socket.connectToHost(m_host, m_port);
    if (!socket.waitForConnected(5000)) {
        qWarning() << "Failed to connect to IMAP server:" << socket.errorString();
        emit statusMessage(QStringLiteral("Failed to connect to IMAP server: %1").arg(socket.errorString()));
        emit progressChanged(100);
        return false;
    }
    if (m_useSsl && !socket.waitForEncrypted(5000)) {
        qWarning() << "TLS handshake failed:" << socket.errorString();
        emit statusMessage(QStringLiteral("TLS handshake failed: %1").arg(socket.errorString()));
        emit progressChanged(100);
        return false;
    }
    if (!socket.waitForReadyRead(5000)) {
        qWarning() << "No greeting from IMAP server";
        emit statusMessage(QStringLiteral("No greeting from IMAP server"));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    while (socket.canReadLine())
        socket.readLine(); // discard greeting lines

    // Login
    QString loginCmd = QStringLiteral("a001 LOGIN %1 %2").arg(m_username, m_password);
    QString resp;
    if (!sendCommand(socket, loginCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a001"), resp) ||
        !resp.contains(QStringLiteral("a001 OK"))) {
        qWarning() << "LOGIN failed:" << resp;
        emit statusMessage(QStringLiteral("LOGIN failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(20);

    // Select folder
    QString selectCmd = QStringLiteral("a002 SELECT \"%1\"").arg(folder.name());
    resp.clear();
    if (!sendCommand(socket, selectCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a002"), resp) ||
        !resp.contains(QStringLiteral("a002 OK"))) {
        qWarning() << "SELECT failed:" << resp;
        emit statusMessage(QStringLiteral("SELECT failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(40);

    // Mark as \\Deleted
    QString storeCmd = QStringLiteral("a003 UID STORE %1 +FLAGS \\Deleted").arg(uid);
    resp.clear();
    if (!sendCommand(socket, storeCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a003"), resp) ||
        !resp.contains(QStringLiteral("a003 OK"))) {
        qWarning() << "STORE Deleted failed:" << resp;
        emit statusMessage(QStringLiteral("STORE Deleted failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(60);

    // EXPUNGE
    QString expungeCmd = QStringLiteral("a004 EXPUNGE");
    resp.clear();
    if (!sendCommand(socket, expungeCmd, resp) ||
        !waitForResponse(socket, QStringLiteral("a004"), resp) ||
        !resp.contains(QStringLiteral("a004 OK"))) {
        qWarning() << "EXPUNGE failed:" << resp;
        emit statusMessage(QStringLiteral("EXPUNGE failed: %1").arg(resp));
        socket.disconnectFromHost();
        emit progressChanged(100);
        return false;
    }
    emit progressChanged(80);

    // Logout
    QString logoutCmd = QStringLiteral("a005 LOGOUT");
    sendCommand(socket, logoutCmd, resp);
    waitForResponse(socket, QStringLiteral("a005"), resp);
    socket.disconnectFromHost();
    // Delete local copy
    if (MailItemDao::remove(uid)) {
        emit statusMessage(QStringLiteral("Email deleted successfully"));
        emit progressChanged(100);
        return true;
    }
    emit statusMessage(QStringLiteral("Failed to delete email"));
    emit progressChanged(100);
    return false;
}

#include "imapsynchronizer.moc"