#include "accountdao.h"

bool AccountDao::insert(const Account& account)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "INSERT INTO Account (email, displayName, type, accessToken, refreshToken, tokenExpires) "
        "VALUES (:email, :displayName, :type, :accessToken, :refreshToken, :tokenExpires)"
    );
    query.bindValue(":email", account.email());
    query.bindValue(":displayName", account.displayName());
    query.bindValue(":type", static_cast<int>(account.type()));
    query.bindValue(":accessToken", account.accessToken());
    query.bindValue(":refreshToken", account.refreshToken());
    query.bindValue(":tokenExpires", account.tokenExpires());

    if (!query.exec()) {
        qWarning() << "Failed to insert account:" << query.lastError().text();
        return false;
    }

    // Optionally set the id on the account object if needed (pass by reference?)
    // Since account is const, we cannot modify it. Caller can retrieve lastInsertId.
    return true;
}

bool AccountDao::update(const Account& account)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare(
        "UPDATE Account SET "
        "email = :email, "
        "displayName = :displayName, "
        "type = :type, "
        "accessToken = :accessToken, "
        "refreshToken = :refreshToken, "
        "tokenExpires = :tokenExpires "
        "WHERE id = :id"
    );
    query.bindValue(":id", account.id());
    query.bindValue(":email", account.email());
    query.bindValue(":displayName", account.displayName());
    query.bindValue(":type", static_cast<int>(account.type()));
    query.bindValue(":accessToken", account.accessToken());
    query.bindValue(":refreshToken", account.refreshToken());
    query.bindValue(":tokenExpires", account.tokenExpires());

    if (!query.exec()) {
        qWarning() << "Failed to update account:" << query.lastError().text();
        return false;
    }
    return true;
}

bool AccountDao::remove(int id)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("DELETE FROM Account WHERE id = :id");
    query.bindValue(":id", id);

    if (!query.exec()) {
        qWarning() << "Failed to delete account:" << query.lastError().text();
        return false;
    }
    return true;
}

Account* AccountDao::findById(int id)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, email, displayName, type, accessToken, refreshToken, tokenExpires FROM Account WHERE id = :id");
    query.bindValue(":id", id);

    if (!query.exec()) {
        qWarning() << "Failed to find account by id:" << query.lastError().text();
        return nullptr;
    }

    if (query.next()) {
        Account* account = new Account();
        account->setId(query.value("id").toLongLong());
        account->setEmail(query.value("email").toString());
        account->setDisplayName(query.value("displayName").toString());
        account->setType(static_cast<AccountType>(query.value("type").toInt()));
        account->setAccessToken(query.value("accessToken").toString());
        account->setRefreshToken(query.value("refreshToken").toString());
        account->setTokenExpires(query.value("tokenExpires").toDateTime());
        return account;
    }

    return nullptr;
}

QVector<Account> AccountDao::findAll()
{
    QVector<Account> accounts;
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    if (!query.exec("SELECT id, email, displayName, type, accessToken, refreshToken, tokenExpires FROM Account")) {
        qWarning() << "Failed to fetch all accounts:" << query.lastError().text();
        return accounts;
    }

    while (query.next()) {
        Account acc;
        acc.setId(query.value(0).toInt());
        acc.setEmail(query.value(1).toString());
        acc.setDisplayName(query.value(2).toString());
        acc.setType(static_cast<AccountType>(query.value(3).toInt()));
        acc.setAccessToken(query.value(4).toString());
        acc.setRefreshToken(query.value(5).toString());
        acc.setTokenExpires(query.value(6).toDateTime());
        accounts.append(acc);
    }
    return accounts;
}

Account* AccountDao::findByEmail(const QString& email)
{
    QSqlDatabase& db = DatabaseManager::instance().database();
    QSqlQuery query(db);
    query.prepare("SELECT id, email, displayName, type, accessToken, refreshToken, tokenExpires FROM Account WHERE email = :email");
    query.bindValue(":email", email);

    if (!query.exec()) {
        qWarning() << "Failed to find account by email:" << query.lastError().text();
        return nullptr;
    }

    if (query.next()) {
        Account* acc = new Account();
        acc->setId(query.value(0).toLongLong());
        acc->setEmail(query.value(1).toString());
        acc->setDisplayName(query.value(2).toString());
        acc->setType(static_cast<AccountType>(query.value(3).toInt()));
        acc->setAccessToken(query.value(4).toString());
        acc->setRefreshToken(query.value(5).toString());
        acc->setTokenExpires(query.value(6).toDateTime());
        return acc;
    }
    return nullptr;
}
