#include "EventDAO.h"

#include <QSqlError>
#include <QSqlQuery>

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

EventInfo parseEvent(const QSqlQuery &query) {
    EventInfo event;
    event.id = query.value("id").toInt();
    event.status = eventStatusFromString(query.value("status").toString());
    event.externalId = query.value("external_id").toInt();
    event.accountId = query.value("account_id").toInt();
    event.deviceId = query.value("device_id").toString();
    event.amount = query.value("amount").toDouble();
    event.phone = query.value("phone").toString();
    event.bankName = query.value("bank_name").toString();
    event.timestamp = DateUtils::fromUtcString(query.value("timestamp").toString());
    event.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
    event.completeTime = DateUtils::fromUtcString(query.value("complete_time").toString());
    return event;
}

int EventDAO::insertEvent(const EventInfo &event) {
    QSqlQuery query(DatabaseManager::instance().database());

    query.prepare(R"(
            INSERT INTO events (
                status, external_id, account_id, amount, phone, bank_name, timestamp, device_id
            ) VALUES (
                :status, :external_id, :account_id, :amount, :phone, :bank_name, :timestamp, :device_id
            )
        )");

    query.bindValue(":status", eventStatusToString(event.status));
    query.bindValue(":external_id", event.externalId);
    query.bindValue(":account_id", event.accountId);
    query.bindValue(":device_id", event.deviceId);
    query.bindValue(":amount", event.amount);
    query.bindValue(":phone", event.phone);
    query.bindValue(":bank_name", event.bankName);
    query.bindValue(":timestamp", event.timestamp);

    if (!query.exec()) {
        qCritical() << "Ошибка при вставке event:" << query.lastError().text();
        return -1;
    }

    return query.lastInsertId().toInt();
}

bool EventDAO::updateEvent(
    const int id,
    const EventStatus &status
) {
    QSqlQuery query(DatabaseManager::instance().database());

    query.prepare(R"(
        UPDATE events SET
            status = :status,
            update_time = :update_time,
            complete_time = :complete_time
        WHERE id = :id
    )");

    query.bindValue(":id", id);
    query.bindValue(":status", eventStatusToString(status));

    if (status == EventStatus::Wait) {
        query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
    } else {
        query.bindValue(":update_time", QVariant(QMetaType(QMetaType::QString)));
    }

    if (status == EventStatus::Complete) {
        query.bindValue(":complete_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
    } else {
        query.bindValue(":complete_time", QVariant(QMetaType(QMetaType::QString)));
    }

    if (!query.exec()) {
        qCritical() << "Ошибка при обновлении event:" << query.lastError().text();
        return false;
    }
    return true;
}

QList<EventInfo> EventDAO::getAllEvents(const EventStatus &status) {
    QList<EventInfo> events;

    QSqlQuery query(DatabaseManager::instance().database());
    query.prepare(R"(
        SELECT id, account_id, device_id, external_id, amount, phone, bank_name, status, update_time, complete_time, timestamp
        FROM events
        WHERE status = :status
    )");
    query.bindValue(":status", eventStatusToString(status));

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

    while (query.next()) {
        events.append(parseEvent(query));
    }

    return events;
}

EventInfo EventDAO::getFirstWaitEventByDeviceId(const QString &key) {
    QSqlQuery query(DatabaseManager::instance().database());
    query.prepare(R"(
        SELECT id, account_id, device_id, external_id, amount, phone, bank_name, status, update_time, complete_time, timestamp
        FROM events
        WHERE status = :status AND device_id = :device_id
        ORDER BY timestamp ASC
        LIMIT 1
    )");
    query.bindValue(":status", eventStatusToString(EventStatus::Wait));
    query.bindValue(":device_id", key);

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

    while (query.next()) {
        return parseEvent(query);
    }
    return {};
}
