#include "EmailTreeModel.h"
#include <QDateTime>
#include <QDate>
#include <QDebug>
#include <algorithm>

EmailTreeModel::EmailTreeModel(QObject *parent)
    : QAbstractItemModel(parent), m_rootItem(new TreeItem(TreeItem::Group))
{
    m_rootItem->type = TreeItem::Group;
    m_rootItem->groupName = "Root";
}

EmailTreeModel::~EmailTreeModel()
{
    deleteTree(m_rootItem);
}

void EmailTreeModel::deleteTree(TreeItem* item)
{
    if (!item) return;
    qDeleteAll(item->children);
    delete item;
}

QModelIndex EmailTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    TreeItem* parentItem;
    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    // Verify parentItem is valid
    if (!parentItem)
        return QModelIndex();

    if (row < 0 || row >= parentItem->children.size())
        return QModelIndex();

    TreeItem* childItem = parentItem->children[row];
    if (!childItem)
        return QModelIndex();

    return createIndex(row, column, childItem);
}

QModelIndex EmailTreeModel::parent(const QModelIndex &child) const
{
    if (!child.isValid())
        return QModelIndex();

    TreeItem* childItem = static_cast<TreeItem*>(child.internalPointer());
    if (!childItem)
        return QModelIndex();

    TreeItem* parentItem = childItem->parent;
    if (!parentItem || parentItem == m_rootItem)
        return QModelIndex();

    return createIndex(parentItem->row, 0, parentItem);
}

int EmailTreeModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;

    TreeItem* parentItem;
    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    return parentItem->children.size();
}

int EmailTreeModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return ColCount;
}

QVariant EmailTreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());

    if (role == MailIdRole) {
        if (item->type == TreeItem::Mail) {
            const MailItem& mail = m_emails[item->mailIndex];
            return mail.id();
        }
        return QVariant();
    }

    if (role == IsGroupRole) {
        return item->type == TreeItem::Group;
    }

    if (role == GroupNameRole && item->type == TreeItem::Group) {
        return item->groupName;
    }

    if (role == GroupIndexRole && item->type == TreeItem::Group) {
        return item->groupIndex;
    }

    if (role == MailIndexRole && item->type == TreeItem::Mail) {
        return item->mailIndex;
    }

    if (role != Qt::DisplayRole && role != Qt::ToolTipRole)
        return QVariant();

    if (item->type == TreeItem::Group) {
        if (index.column() == ColSubject) {
            return QString("%1 (%2)").arg(item->groupName).arg(item->children.size());
        }
        return QVariant();
    }

    // Mail item
    if (item->type == TreeItem::Mail) {
        if (item->mailIndex < 0 || item->mailIndex >= m_emails.size()) {
            return QVariant();
        }
        const MailItem& mail = m_emails[item->mailIndex];
        
        switch (index.column()) {
    case ColSubject:
        return mail.subject().isEmpty() ? "(Sin asunto)" : mail.subject();
    case ColSender:
        return mail.sender();
    case ColDate: {
        if (!mail.date().isValid()) return QVariant();
        QDateTime dt = mail.date();
        QDate today = QDate::currentDate();
        if (dt.date() == today) {
            return dt.toString("HH:mm");
        } else if (dt.date() == today.addDays(-1)) {
            return "Ayer " + dt.toString("HH:mm");
        } else if (dt.date().year() == today.year()) {
            return dt.toString("ddd dd/MM HH:mm");
        } else {
            return dt.toString("dd/MM/yyyy HH:mm");
        }
    }
    default:
                return QVariant();
            }
        }
        return QVariant();
    }

QVariant EmailTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        switch (section) {
        case ColSubject: return "Asunto";
        case ColSender: return "De";
        case ColDate: return "Fecha";
        default: return QVariant();
        }
    }
    return QAbstractItemModel::headerData(section, orientation, role);
}

Qt::ItemFlags EmailTreeModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;

    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
    
    Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    if (item->type == TreeItem::Group) {
        // Groups don't need special flags for expand/collapse in Qt6
    }
    return f;
}

void EmailTreeModel::setEmails(const QVector<MailItem> &emails)
{
    beginResetModel();
    m_emails = emails;
    // Clear tree properly without deleting root
    qDeleteAll(m_rootItem->children);
    m_rootItem->children.clear();
    setupModelData();
    endResetModel();
}

void EmailTreeModel::clear()
{
    beginResetModel();
    m_emails.clear();
    deleteTree(m_rootItem);
    m_rootItem = new TreeItem(TreeItem::Group);
    m_rootItem->type = TreeItem::Group;
    m_rootItem->groupName = "Root";
    endResetModel();
}

void EmailTreeModel::setGroupMode(GroupMode mode)
{
    if (m_groupMode == mode) return;
    
    // Clear existing tree first
    beginResetModel();
    m_groupMode = mode;
    qDeleteAll(m_rootItem->children);
    m_rootItem->children.clear();
    setupModelData();
    endResetModel();
}

void EmailTreeModel::setupModelData()
{
    if (m_groupMode == NoGrouping) {
        // Flat list - all mails directly under root
        for (int i = 0; i < m_emails.size(); ++i) {
            if (i < 0 || i >= m_emails.size()) continue;
            TreeItem* mailItem = new TreeItem(TreeItem::Mail, m_rootItem);
            mailItem->mailIndex = i;
            mailItem->row = m_rootItem->children.size();
            m_rootItem->children.append(mailItem);
        }
    } else {
        // Grouped by date
        buildGroups();
    }
}

void EmailTreeModel::buildGroups()
{
    // Sort emails by date descending (newest first)
    QVector<int> indices(m_emails.size());
    std::iota(indices.begin(), indices.end(), 0);
    std::sort(indices.begin(), indices.end(), [this](int a, int b) {
        const QDateTime& dateA = m_emails[a].date();
        const QDateTime& dateB = m_emails[b].date();
        if (!dateA.isValid() && !dateB.isValid()) return false;
        if (!dateA.isValid()) return false;
        if (!dateB.isValid()) return true;
        return dateA > dateB;
    });

    // Group by date - store both groupName and representative date for sorting
    struct GroupData {
        QString name;
        QDateTime representativeDate; // earliest date in group for sorting
        QVector<int> mailIndices;
    };
    QMap<QString, GroupData> groupsMap;
    
    for (int idx : indices) {
        if (idx < 0 || idx >= m_emails.size()) continue;
        const QDateTime& dt = m_emails[idx].date();
        if (!dt.isValid()) continue;
        
        QString groupName = groupNameForDate(dt);
        auto& g = groupsMap[groupName];
        g.name = groupName;
        g.mailIndices.append(idx);
        // Keep the earliest (most recent) date as representative for sorting groups chronologically
        if (!g.representativeDate.isValid() || dt > g.representativeDate) {
            g.representativeDate = dt;
        }
    }

    // Sort groups by representative date descending (newest group first)
    QVector<GroupData> sortedGroups;
    sortedGroups.reserve(groupsMap.size());
    for (auto it = groupsMap.constBegin(); it != groupsMap.constEnd(); ++it) {
        if (!it.value().mailIndices.isEmpty()) {
            sortedGroups.append(it.value());
        }
    }
    std::sort(sortedGroups.begin(), sortedGroups.end(), [](const GroupData& a, const GroupData& b) {
        // Newest group first (descending by representative date)
        if (!a.representativeDate.isValid() && !b.representativeDate.isValid()) return false;
        if (!a.representativeDate.isValid()) return false;
        if (!b.representativeDate.isValid()) return true;
        return a.representativeDate > b.representativeDate;
    });

    // Create tree items in chronological group order
    int groupIdx = 0;
    for (const GroupData& g : sortedGroups) {
        TreeItem* groupItem = new TreeItem(TreeItem::Group, m_rootItem);
        groupItem->groupName = g.name;
        groupItem->groupIndex = groupIdx++;
        groupItem->row = m_rootItem->children.size();
        m_rootItem->children.append(groupItem);

        for (int mailIdx : g.mailIndices) {
            if (mailIdx < 0 || mailIdx >= m_emails.size()) continue;
            TreeItem* mailItem = new TreeItem(TreeItem::Mail, groupItem);
            mailItem->mailIndex = mailIdx;
            mailItem->row = groupItem->children.size();
            groupItem->children.append(mailItem);
        }
    }
}

QString EmailTreeModel::groupNameForDate(const QDateTime &date) const
{
    if (!date.isValid()) return "Sin fecha";

    QDate emailDate = date.date();
    QDate today = QDate::currentDate();

    int daysDiff = today.daysTo(emailDate);

    if (daysDiff == 0) {
        return "Hoy";
    } else if (daysDiff == -1) {
        return "Ayer";
    } else if (daysDiff > -7 && daysDiff < 0) {
        // This week
        return "Esta semana";
    } else if (daysDiff >= -13 && daysDiff <= -7) {
        return "Semana pasada";
    } else if (daysDiff >= -20 && daysDiff <= -14) {
        return "Hace dos semanas";
    } else if (emailDate.month() == today.month() && emailDate.year() == today.year()) {
        return "Este mes";
    } else if (emailDate.year() == today.year()) {
        static const QString months[] = {
            "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
            "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
        };
        return months[emailDate.month() - 1];
    } else {
        return QString("%1").arg(emailDate.year());
    }
}

int EmailTreeModel::groupIndexForDate(const QDateTime &date) const
{
    // Not used directly but kept for reference
    return 0;
}