#include <QSqlQuery>
#include <QSqlError>
#include "AccountDAO.h"

#include "db/AccountInfo.h"
#include "DatabaseManager.h"
#include "time/DateUtils.h"

bool AccountDAO::upsertAccount(const AccountInfo &info) {
    QSqlQuery query(DatabaseManager::instance().database());

    query.prepare(R"(
        INSERT INTO accounts (device_id, app_name, last_numbers, amount, update_time, status, description)
        VALUES (:device_id, :app_name, :last_numbers, :amount, :update_time, :status, :description)
        ON CONFLICT(device_id, app_name, last_numbers)
        DO UPDATE SET
            amount = excluded.amount,
            update_time = excluded.update_time,
            status = excluded.status,
            description = excluded.description
    )");

    query.bindValue(":device_id", info.deviceId);
    query.bindValue(":app_name", info.appName);
    query.bindValue(":last_numbers", info.lastNumbers);
    query.bindValue(":amount", info.amount);
    query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
    query.bindValue(":status", accountStatusToString(info.status));
    query.bindValue(":description", info.description);

    if (!query.exec()) {
        qWarning() << "Ошибка при вставке/обновлении account:" << query.lastError().text();
        return false;
    }

    return true;
}

bool AccountDAO::deleteAccount(const int id) {
    QSqlQuery query(DatabaseManager::instance().database());
    query.prepare("DELETE FROM accounts WHERE id = :id");
    query.bindValue(":id", id);
    return query.exec();
}

AccountInfo parseAccount(const QSqlQuery &query) {
    AccountInfo acc;
    acc.id = query.value("id").toInt();
    acc.deviceId = query.value("device_id").toString();
    acc.appName = query.value("app_name").toString();
    acc.lastNumbers = query.value("last_numbers").toString();
    acc.amount = query.value("amount").toDouble();
    acc.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
    acc.status = accountStatusFromString(query.value("status").toString());
    acc.description = query.value("description").toString();
    return acc;
}

QList<AccountInfo> AccountDAO::getAccounts(const QString &deviceId, const QString &appName) {
    QList<AccountInfo> accounts;
    QSqlQuery query(DatabaseManager::instance().database());

    query.prepare(R"(
        SELECT id, device_id, app_name, last_numbers, amount, update_time, status, description
        FROM accounts
        WHERE device_id = :device_id AND app_name = :app_name
    )");

    query.bindValue(":device_id", deviceId);
    query.bindValue(":app_name", appName);

    if (!query.exec()) {
        qWarning() << "Ошибка при получении accounts:" << query.lastError().text();
        return accounts;
    }

    while (query.next()) {
        accounts.append(parseAccount(query));
    }

    return accounts;
}

AccountInfo AccountDAO::getAccountById(const int accountId) {
    QSqlQuery query(DatabaseManager::instance().database());

    query.prepare(R"(
        SELECT id, device_id, app_name, last_numbers, amount, update_time, status, description
        FROM accounts
        WHERE id = :id
        LIMIT 1
    )");

    query.bindValue(":id", accountId);

    if (!query.exec()) {
        qWarning() << "Ошибка при получении account по ID:" << query.lastError().text();
        return {};
    }

    if (query.next()) {
        return parseAccount(query);
    }
    return {};
}

AccountInfo AccountDAO::findAppAccount(const QString &deviceId, const QString &appName, const QString &lastNumber) {
    QSqlQuery query(DatabaseManager::instance().database());

    query.prepare(R"(
        SELECT id, device_id, app_name, last_numbers, amount, update_time, status, description
        FROM accounts
        WHERE app_name = :appName AND last_numbers = :lastNumber AND device_id = :deviceId
        LIMIT 1
    )");

    query.bindValue(":deviceId", deviceId);
    query.bindValue(":appName", appName);
    query.bindValue(":lastNumber", lastNumber);

    if (!query.exec()) {
        qWarning() << "Ошибка при получении account по ID:" << query.lastError().text();
        return {};
    }

    if (query.next()) {
        return parseAccount(query);
    }

    return {};
}
