#include "categorydao.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QDateTime>

bool CategoryDao::insert(Category& cat)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "INSERT INTO Category (accountId, name, color, parentCategoryId, sortOrder, createdAt) "
        "VALUES (:accountId, :name, :color, :parentCategoryId, :sortOrder, :createdAt)");
    
    query.bindValue(":accountId", cat.accountId >= 0 ? cat.accountId : QVariant());
    query.bindValue(":name", cat.name);
    query.bindValue(":color", cat.color.name(QColor::HexArgb));
    query.bindValue(":parentCategoryId", cat.parentCategoryId >= 0 ? cat.parentCategoryId : QVariant());
    query.bindValue(":sortOrder", cat.sortOrder);
    query.bindValue(":createdAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
    
    if (!query.exec()) {
        qDebug() << "[CategoryDao] Insert failed:" << query.lastError().text();
        return false;
    }
    
    cat.id = query.lastInsertId().toLongLong();
    return true;
}

bool CategoryDao::update(const Category& cat)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "UPDATE Category SET accountId = :accountId, name = :name, color = :color, "
        "parentCategoryId = :parentCategoryId, sortOrder = :sortOrder "
        "WHERE id = :id");
    
    query.bindValue(":id", cat.id);
    query.bindValue(":accountId", cat.accountId >= 0 ? cat.accountId : QVariant());
    query.bindValue(":name", cat.name);
    query.bindValue(":color", cat.color.name(QColor::HexArgb));
    query.bindValue(":parentCategoryId", cat.parentCategoryId >= 0 ? cat.parentCategoryId : QVariant());
    query.bindValue(":sortOrder", cat.sortOrder);
    
    if (!query.exec()) {
        qDebug() << "[CategoryDao] Update failed:" << query.lastError().text();
        return false;
    }
    
    return true;
}

bool CategoryDao::remove(qint64 id)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("DELETE FROM Category WHERE id = :id");
    query.bindValue(":id", id);
    
    if (!query.exec()) {
        qDebug() << "[CategoryDao] Remove failed:" << query.lastError().text();
        return false;
    }
    
    return true;
}

std::optional<Category> CategoryDao::findById(qint64 id)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, accountId, name, color, parentCategoryId, sortOrder, createdAt FROM Category WHERE id = :id");
    query.bindValue(":id", id);
    
    if (!query.exec() || !query.next()) {
        return std::nullopt;
    }
    
    Category cat;
    cat.id = query.value("id").toLongLong();
    cat.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
    cat.name = query.value("name").toString();
    cat.color = QColor(query.value("color").toString());
    cat.parentCategoryId = query.value("parentCategoryId").isNull() ? -1 : query.value("parentCategoryId").toLongLong();
    cat.sortOrder = query.value("sortOrder").toInt();
    cat.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
    
    return cat;
}

QVector<Category> CategoryDao::findByAccount(qint64 accountId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, accountId, name, color, parentCategoryId, sortOrder, createdAt FROM Category WHERE accountId = :accountId ORDER BY sortOrder, name");
    query.bindValue(":accountId", accountId);
    
    QVector<Category> cats;
    if (query.exec()) {
        while (query.next()) {
            Category cat;
            cat.id = query.value("id").toLongLong();
            cat.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
            cat.name = query.value("name").toString();
            cat.color = QColor(query.value("color").toString());
            cat.parentCategoryId = query.value("parentCategoryId").isNull() ? -1 : query.value("parentCategoryId").toLongLong();
            cat.sortOrder = query.value("sortOrder").toInt();
            cat.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
            cats.append(cat);
        }
    }
    return cats;
}

QVector<Category> CategoryDao::findGlobal()
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.exec("SELECT id, accountId, name, color, parentCategoryId, sortOrder, createdAt FROM Category WHERE accountId IS NULL ORDER BY sortOrder, name");
    
    QVector<Category> cats;
    while (query.next()) {
        Category cat;
        cat.id = query.value("id").toLongLong();
        cat.accountId = -1;
        cat.name = query.value("name").toString();
        cat.color = QColor(query.value("color").toString());
        cat.parentCategoryId = query.value("parentCategoryId").isNull() ? -1 : query.value("parentCategoryId").toLongLong();
        cat.sortOrder = query.value("sortOrder").toInt();
        cat.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
        cats.append(cat);
    }
    return cats;
}

QVector<Category> CategoryDao::findAll()
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.exec("SELECT id, accountId, name, color, parentCategoryId, sortOrder, createdAt FROM Category ORDER BY sortOrder, name");
    
    QVector<Category> cats;
    while (query.next()) {
        Category cat;
        cat.id = query.value("id").toLongLong();
        cat.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
        cat.name = query.value("name").toString();
        cat.color = QColor(query.value("color").toString());
        cat.parentCategoryId = query.value("parentCategoryId").isNull() ? -1 : query.value("parentCategoryId").toLongLong();
        cat.sortOrder = query.value("sortOrder").toInt();
        cat.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
        cats.append(cat);
    }
    return cats;
}

QVector<Category> CategoryDao::findChildren(qint64 parentId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, accountId, name, color, parentCategoryId, sortOrder, createdAt FROM Category WHERE parentCategoryId = :parentId ORDER BY sortOrder, name");
    query.bindValue(":parentId", parentId);
    
    QVector<Category> cats;
    if (query.exec()) {
        while (query.next()) {
            Category cat;
            cat.id = query.value("id").toLongLong();
            cat.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
            cat.name = query.value("name").toString();
            cat.color = QColor(query.value("color").toString());
            cat.parentCategoryId = query.value("parentCategoryId").isNull() ? -1 : query.value("parentCategoryId").toLongLong();
            cat.sortOrder = query.value("sortOrder").toInt();
            cat.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
            cats.append(cat);
        }
    }
    return cats;
}

bool CategoryDao::assignToMail(qint64 mailId, qint64 categoryId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("INSERT OR IGNORE INTO MailCategory (mailCopyId, categoryId, assignedAt) VALUES (:mailId, :categoryId, :assignedAt)");
    query.bindValue(":mailId", mailId);
    query.bindValue(":categoryId", categoryId);
    query.bindValue(":assignedAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
    
    if (!query.exec()) {
        qDebug() << "[CategoryDao] assignToMail failed:" << query.lastError().text();
        return false;
    }
    return true;
}

bool CategoryDao::removeFromMail(qint64 mailId, qint64 categoryId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("DELETE FROM MailCategory WHERE mailCopyId = :mailId AND categoryId = :categoryId");
    query.bindValue(":mailId", mailId);
    query.bindValue(":categoryId", categoryId);
    
    if (!query.exec()) {
        qDebug() << "[CategoryDao] removeFromMail failed:" << query.lastError().text();
        return false;
    }
    return true;
}

QVector<qint64> CategoryDao::categoriesForMail(qint64 mailId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT categoryId FROM MailCategory WHERE mailCopyId = :mailId");
    query.bindValue(":mailId", mailId);
    
    QVector<qint64> catIds;
    if (query.exec()) {
        while (query.next()) {
            catIds.append(query.value("categoryId").toLongLong());
        }
    }
    return catIds;
}

bool CategoryDao::reorder(const QVector<qint64>& ids)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    db.transaction();
    
    for (int i = 0; i < ids.size(); ++i) {
        QSqlQuery query(db);
        query.prepare("UPDATE Category SET sortOrder = :sortOrder WHERE id = :id");
        query.bindValue(":sortOrder", i);
        query.bindValue(":id", ids[i]);
        if (!query.exec()) {
            db.rollback();
            qDebug() << "[CategoryDao] reorder failed:" << query.lastError().text();
            return false;
        }
    }
    
    db.commit();
    return true;
}