#include "mailservice.h"
#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrent/QtConcurrent>
#include <QDebug>

MailService::MailService(AccountService *accountService, QObject *parent)
    : QObject(parent)
    , m_composer(new EmailComposerBridge(this))
    , m_accountService(accountService)
{
}

QVector<MailItem> MailService::getMails(const QString &folderId)
{
    return MailItemDao::findByFolderId(folderId.toInt());
}

void MailService::sendMail(const MailItem &mail, const QString &accountId)
{
    // For now we just simulate sending by using EmailComposerBridge
    // In a real implementation, this would use SMTP settings from the account.
    Q_UNUSED(mail);
    Q_UNUSED(accountId);
    // Emit success immediately; actual sending would be asynchronous.
    QMetaObject::invokeMethod(this, "mailSent", Qt::QueuedConnection,
                              Q_ARG(QString, QString()));
}

void MailService::fetchMails(const QString &accountId, const QString &folderId)
{
    // Determine provider type from account
    if (!m_accountService) {
        emit mailFetchError(accountId, folderId, tr("AccountService not available"));
        return;
    }
    Account *acc = m_accountService->findAccountById(accountId.toLongLong());
    QString providerType = QStringLiteral("imap"); // fallback
    if (acc) {
        switch (acc->type()) {
        case AccountType::IMAP:
            providerType = QStringLiteral("imap");
            break;
        case AccountType::POP3:
            providerType = QStringLiteral("pop3");
            break;
        case AccountType::Gmail:
            providerType = QStringLiteral("gmail");
            break;
        case AccountType::Outlook:
            providerType = QStringLiteral("outlook");
            break;
        default:
            providerType = QStringLiteral("imap");
            break;
        }
    }

    Synchronizer *sync = SynchronizerProvider::instance().createSynchronizer(accountId, providerType);
    if (!sync) {
        emit mailFetchError(accountId, folderId, tr("Failed to create synchronizer"));
        return;
    }

    // Connect progress signals (if they exist) using string-based syntax for compatibility
    QObject::connect(sync, SIGNAL(progressChanged(int)), this, SIGNAL(progressChanged(int)), Qt::QueuedConnection);
    QObject::connect(sync, SIGNAL(statusMessage(const QString&)), this, SIGNAL(statusMessage(const QString&)), Qt::QueuedConnection);

    QFuture<QVector<MailItem>> future = QtConcurrent::run([=]() {
        // SinceUid = 0 for full sync; could be stored per folder but omitted for simplicity
        return sync->fetchMailItems(folderId, 0);
    });

    QFutureWatcher<QVector<MailItem>> *watcher = new QFutureWatcher<QVector<MailItem>>(this);
    QObject::connect(watcher, &QFutureWatcher<QVector<MailItem>>::finished, this, [=]() {
        // Disconnect progress signals
        QObject::disconnect(sync, SIGNAL(progressChanged(int)), this, SIGNAL(progressChanged(int)));
        QObject::disconnect(sync, SIGNAL(statusMessage(const QString&)), this, SIGNAL(statusMessage(const QString&)));
        QVector<MailItem> items = watcher->result();
        watcher->deleteLater();
        emit mailFetched(accountId, folderId, items);
    });
    watcher->setFuture(future);
}

void MailService::moveMail(const QString &mailItemId, const QString &targetFolderId)
{
    bool ok;
    qint64 id = mailItemId.toLongLong(&ok);
    if (!ok) return;
    std::optional<MailItem> opt = MailItemDao::findById(id);
    if (!opt) return;
    MailItem item = *opt;
    item.setFolderId(targetFolderId.toInt());
    if (MailItemDao::update(item))
        emit mailMoved(mailItemId);
}

void MailService::deleteMail(const QString &mailItemId)
{
    bool ok;
    qint64 id = mailItemId.toLongLong(&ok);
    if (!ok) return;
    if (MailItemDao::remove(id))
        emit mailDeleted(mailItemId);
}

void MailService::markAsRead(const QString &mailItemId, bool read)
{
    bool ok;
    qint64 id = mailItemId.toLongLong(&ok);
    if (!ok) return;
    std::optional<MailItem> opt = MailItemDao::findById(id);
    if (!opt) return;
    MailItem item = *opt;
    item.setRead(read);
    if (MailItemDao::update(item))
        emit mailReadStateChanged(mailItemId, read);
}

#include "mailservice.moc"