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

bool SignatureDao::insert(Signature& sig)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "INSERT INTO Signature (accountId, name, html, isDefault, createdAt, updatedAt) "
        "VALUES (:accountId, :name, :html, :isDefault, :createdAt, :updatedAt)");
    
    query.bindValue(":accountId", sig.accountId >= 0 ? sig.accountId : QVariant());
    query.bindValue(":name", sig.name);
    query.bindValue(":html", sig.html);
    query.bindValue(":isDefault", sig.isDefault ? 1 : 0);
    query.bindValue(":createdAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
    query.bindValue(":updatedAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
    
    if (!query.exec()) {
        qDebug() << "[SignatureDao] Insert failed:" << query.lastError().text();
        return false;
    }
    
    sig.id = query.lastInsertId().toLongLong();
    return true;
}

bool SignatureDao::update(const Signature& sig)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "UPDATE Signature SET accountId = :accountId, name = :name, html = :html, "
        "isDefault = :isDefault, updatedAt = :updatedAt "
        "WHERE id = :id");
    
    query.bindValue(":id", sig.id);
    query.bindValue(":accountId", sig.accountId >= 0 ? sig.accountId : QVariant());
    query.bindValue(":name", sig.name);
    query.bindValue(":html", sig.html);
    query.bindValue(":isDefault", sig.isDefault ? 1 : 0);
    query.bindValue(":updatedAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
    
    if (!query.exec()) {
        qDebug() << "[SignatureDao] Update failed:" << query.lastError().text();
        return false;
    }
    
    return true;
}

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

std::optional<Signature> SignatureDao::findById(qint64 id)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, accountId, name, html, isDefault, createdAt, updatedAt FROM Signature WHERE id = :id");
    query.bindValue(":id", id);
    
    if (!query.exec() || !query.next()) {
        return std::nullopt;
    }
    
    Signature sig;
    sig.id = query.value("id").toLongLong();
    sig.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
    sig.name = query.value("name").toString();
    sig.html = query.value("html").toString();
    sig.isDefault = query.value("isDefault").toBool();
    sig.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
    sig.updatedAt = QDateTime::fromString(query.value("updatedAt").toString(), Qt::ISODate);
    
    return sig;
}

QVector<Signature> SignatureDao::findByAccount(qint64 accountId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    if (accountId >= 0) {
        query.prepare("SELECT id, accountId, name, html, isDefault, createdAt, updatedAt FROM Signature WHERE accountId = :accountId OR accountId IS NULL ORDER BY name");
        query.bindValue(":accountId", accountId);
    } else {
        query.prepare("SELECT id, accountId, name, html, isDefault, createdAt, updatedAt FROM Signature WHERE accountId IS NULL ORDER BY name");
    }
    
    QVector<Signature> sigs;
    if (query.exec()) {
        while (query.next()) {
            Signature sig;
            sig.id = query.value("id").toLongLong();
            sig.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
            sig.name = query.value("name").toString();
            sig.html = query.value("html").toString();
            sig.isDefault = query.value("isDefault").toBool();
            sig.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
            sig.updatedAt = QDateTime::fromString(query.value("updatedAt").toString(), Qt::ISODate);
            sigs.append(sig);
        }
    }
    return sigs;
}

QVector<Signature> SignatureDao::findGlobal()
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.exec("SELECT id, accountId, name, html, isDefault, createdAt, updatedAt FROM Signature WHERE accountId IS NULL ORDER BY name");
    
    QVector<Signature> sigs;
    while (query.next()) {
        Signature sig;
        sig.id = query.value("id").toLongLong();
        sig.accountId = -1;
        sig.name = query.value("name").toString();
        sig.html = query.value("html").toString();
        sig.isDefault = query.value("isDefault").toBool();
        sig.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
        sig.updatedAt = QDateTime::fromString(query.value("updatedAt").toString(), Qt::ISODate);
        sigs.append(sig);
    }
    return sigs;
}

QVector<Signature> SignatureDao::findAll()
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.exec("SELECT id, accountId, name, html, isDefault, createdAt, updatedAt FROM Signature ORDER BY name");
    
    QVector<Signature> sigs;
    while (query.next()) {
        Signature sig;
        sig.id = query.value("id").toLongLong();
        sig.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
        sig.name = query.value("name").toString();
        sig.html = query.value("html").toString();
        sig.isDefault = query.value("isDefault").toBool();
        sig.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
        sig.updatedAt = QDateTime::fromString(query.value("updatedAt").toString(), Qt::ISODate);
        sigs.append(sig);
    }
    return sigs;
}

std::optional<Signature> SignatureDao::findDefault(qint64 accountId)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "SELECT id, accountId, name, html, isDefault, createdAt, updatedAt "
        "FROM Signature "
        "WHERE (accountId = :accountId OR accountId IS NULL) AND isDefault = 1 "
        "ORDER BY accountId DESC LIMIT 1");
    query.bindValue(":accountId", accountId >= 0 ? accountId : QVariant());
    
    if (!query.exec() || !query.next()) {
        return std::nullopt;
    }
    
    Signature sig;
    sig.id = query.value("id").toLongLong();
    sig.accountId = query.value("accountId").isNull() ? -1 : query.value("accountId").toLongLong();
    sig.name = query.value("name").toString();
    sig.html = query.value("html").toString();
    sig.isDefault = query.value("isDefault").toBool();
    sig.createdAt = QDateTime::fromString(query.value("createdAt").toString(), Qt::ISODate);
    sig.updatedAt = QDateTime::fromString(query.value("updatedAt").toString(), Qt::ISODate);
    
    return sig;
}

bool SignatureDao::setDefault(qint64 id, bool isDefault)
{
    QSqlDatabase db = DatabaseManager::instance().database();
    db.transaction();
    
    // First unset all defaults for the same account
    QSqlQuery query(db);
    query.prepare(
        "UPDATE Signature SET isDefault = 0 WHERE accountId = "
        "(SELECT accountId FROM Signature WHERE id = :id)");
    query.bindValue(":id", id);
    if (!query.exec()) {
        db.rollback();
        return false;
    }
    
    // Set the new default
    query.prepare("UPDATE Signature SET isDefault = :isDefault, updatedAt = :updatedAt WHERE id = :id");
    query.bindValue(":id", id);
    query.bindValue(":isDefault", isDefault ? 1 : 0);
    query.bindValue(":updatedAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
    
    if (!query.exec()) {
        db.rollback();
        qDebug() << "[SignatureDao] setDefault failed:" << query.lastError().text();
        return false;
    }
    
    db.commit();
    return true;
}