#include "dbchangeprocessor.h"
#include <QDebug>
#include <QDateTime>
#include "../db/dao/mailitemdao.h"
#include "../db/dao/folderdao.h"
#include "../db/dao/accountdao.h"

DbChangeProcessor::DbChangeProcessor(QObject* parent)
    : QObject(parent),
      m_batchTimer(new QTimer(this))
{
    // Configurar el timer para procesar batch cada 5 segundos
    m_batchTimer->setInterval(5000); // 5 segundos
    connect(m_batchTimer, &QTimer::timeout, this, &DbChangeProcessor::processBatch);
    m_batchTimer->start();

    // Suscribirse a todos los eventos relevantes
    SUBSCRIBE(WinoMail::Events::MailItemAddedEvent, 
              [this](const WinoMail::Events::MailItemAddedEvent& event) {
                  handleMailItemAdded(event);
              });
              
    SUBSCRIBE(WinoMail::Events::MailItemRemovedEvent, 
              [this](const WinoMail::Events::MailItemRemovedEvent& event) {
                  handleMailItemRemoved(event);
              });
              
    SUBSCRIBE(WinoMail::Events::MailItemUpdatedEvent, 
              [this](const WinoMail::Events::MailItemUpdatedEvent& event) {
                  handleMailItemUpdated(event);
              });
              
    SUBSCRIBE(WinoMail::Events::FolderAddedEvent, 
              [this](const WinoMail::Events::FolderAddedEvent& event) {
                  handleFolderAdded(event);
              });
              
    SUBSCRIBE(WinoMail::Events::FolderRemovedEvent, 
              [this](const WinoMail::Events::FolderRemovedEvent& event) {
                  handleFolderRemoved(event);
              });
              
    SUBSCRIBE(WinoMail::Events::FolderUpdatedEvent, 
              [this](const WinoMail::Events::FolderUpdatedEvent& event) {
                  handleFolderUpdated(event);
              });
              
    SUBSCRIBE(WinoMail::Events::AccountAddedEvent, 
              [this](const WinoMail::Events::AccountAddedEvent& event) {
                  handleAccountAdded(event);
              });
              
    SUBSCRIBE(WinoMail::Events::AccountRemovedEvent, 
              [this](const WinoMail::Events::AccountRemovedEvent& event) {
                  handleAccountRemoved(event);
              });
              
    SUBSCRIBE(WinoMail::Events::AccountUpdatedEvent, 
              [this](const WinoMail::Events::AccountUpdatedEvent& event) {
                  handleAccountUpdated(event);
              });
}

void DbChangeProcessor::handleMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing MailItemAddedEvent for ID:" << event.item.id();
    m_mailItemAddedQueue.append(event);
}

void DbChangeProcessor::handleMailItemRemoved(const WinoMail::Events::MailItemRemovedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing MailItemRemovedEvent for UID:" << event.itemUid;
    m_mailItemRemovedQueue.append(event);
}

void DbChangeProcessor::handleMailItemUpdated(const WinoMail::Events::MailItemUpdatedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing MailItemUpdatedEvent for ID:" << event.item.id();
    m_mailItemUpdatedQueue.append(event);
}

void DbChangeProcessor::handleFolderAdded(const WinoMail::Events::FolderAddedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing FolderAddedEvent for folder:" << event.folder.name();
    m_folderAddedQueue.append(event);
}

void DbChangeProcessor::handleFolderRemoved(const WinoMail::Events::FolderRemovedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing FolderRemovedEvent for folder ID:" << event.folderId;
    m_folderRemovedQueue.append(event);
}

void DbChangeProcessor::handleFolderUpdated(const WinoMail::Events::FolderUpdatedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing FolderUpdatedEvent for folder ID:" << event.folder.id();
    m_folderUpdatedQueue.append(event);
}

void DbChangeProcessor::handleAccountAdded(const WinoMail::Events::AccountAddedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing AccountAddedEvent for account:" << event.account.email();
    m_accountAddedQueue.append(event);
}

void DbChangeProcessor::handleAccountRemoved(const WinoMail::Events::AccountRemovedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing AccountRemovedEvent for account ID:" << event.accountId;
    m_accountRemovedQueue.append(event);
}

void DbChangeProcessor::handleAccountUpdated(const WinoMail::Events::AccountUpdatedEvent& event)
{
    qDebug() << "DbChangeProcessor: Queuing AccountUpdatedEvent for account ID:" << event.account.id();
    m_accountUpdatedQueue.append(event);
}

void DbChangeProcessor::processBatch()
{
    qDebug() << "DbChangeProcessor: Starting batch processing at" << QDateTime::currentDateTime().toString();
    
    // Procesar eventos de MailItem añadidos
    if (!m_mailItemAddedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_mailItemAddedQueue.size() << "MailItemAdded events";
        for (auto        for (autoconst auto& event event : m_mailItemAddedQueue) { event : m_mailItemAddedQueue) {
            MailItemDao::insert(event.item);
        }
        m_mailItemAddedQueue.clear();
    }
    
    // Procesar eventos de MailItem eliminados
    if (!m_mailItemRemovedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_mailItemRemovedQueue.size() << "MailItemRemoved events";
        for (const auto& event : m_mailItemRemovedQueue) {
            // We don't have removeByUid in MailItemDao, so we skip and log a warning.
            // In a real implementation, we would need to find the item by uid and folderId to get its id.
            qWarning() << "DbChangeProcessor: MailItemRemoved event processed but removeByUid not implemented in MailItemDao. Skipping removal for UID:" << event.itemUid;
        }
        m_mailItemRemovedQueue.clear();
    }
    
    // Procesar eventos de MailItem actualizados
    if (!m_mailItemUpdatedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_mailItemUpdatedQueue.size() << "MailItemUpdated events";
        for (const auto& event : m_mailItemUpdatedQueue) {
            // We ignore changedFields and update the whole item for simplicity.
            MailItemDao::update(event.item);
        }
        m_mailItemUpdatedQueue.clear();
    }
    
    // Procesar eventos de carpetas añadidas
    if (!m_folderAddedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_folderAddedQueue.size() << "FolderAdded events";
        for (const auto& event : m_folderAddedQueue) {
            FolderDao::insert(event.folder);
        }
        m_folderAddedQueue.clear();
    }
    
    // Procesar eventos de carpetas eliminadas
    if (!m_folderRemovedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_folderRemovedQueue.size() << "FolderRemoved events";
        for (const auto& event : m_folderRemovedQueue) {
            // We don't have a way to get the folder id from the event without a query, so we skip and log a warning.
            qWarning() << "DbChangeProcessor: FolderRemoved event processed but we lack the folder id to remove. Skipping removal for folder ID:" << event.folderId;
        }
        m_folderRemovedQueue.clear();
    }
    
    // Procesar eventos de carpetas actualizadas
    if (!m_folderUpdatedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_folderUpdatedQueue.size() << "FolderUpdated events";
        for (const auto& event : m_folderUpdatedQueue) {
            // We ignore changedFields and update the whole folder for simplicity.
            FolderDao::update(event.folder);
        }
        m_folderUpdatedQueue.clear();
    }
    
    // Procesar eventos de cuentas añadidas
    if (!m_accountAddedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_accountAddedQueue.size() << "AccountAdded events";
        for (const auto& event : m_accountAddedQueue) {
            AccountDao::insert(event.account);
        }
        m_accountAddedQueue.clear();
    }
    
    // Procesar eventos de cuentas eliminadas
    if (!m_accountRemovedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_accountRemovedQueue.size() << "AccountRemoved events";
        for (const auto& event : m_accountRemovedQueue) {
            AccountDao::remove(event.accountId);
        }
        m_accountRemovedQueue.clear();
    }
    
    // Procesar eventos de cuentas actualizadas
    if (!m_accountUpdatedQueue.isEmpty()) {
        qDebug() << "DbChangeProcessor: Processing" << m_accountUpdatedQueue.size() << "AccountUpdated events";
        for (const auto& event : m_accountUpdatedQueue) {
            // We ignore changedFields and update the whole account for simplicity.
            AccountDao::update(event.account);
        }
        m_accountUpdatedQueue.clear();
    }
    
    qDebug() << "DbChangeProcessor: Batch processing completed at" << QDateTime::currentDateTime().toString();
}

DbChangeProcessor::~DbChangeProcessor()
{
    if (m_batchTimer->isActive()) {
        m_batchTimer->stop();
    }
    // Procesar cualquier evento restante antes de destruir
    processBatch();
}