// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/debug.h"
#include "core/hle/kernel/Objects/event_queue.h"

namespace Core::Kernel {

EqueueInternal::~EqueueInternal() = default;

int EqueueInternal::addEvent(const EqueueEvent& event) {
    std::scoped_lock lock{m_mutex};

    if (m_events.size() > 0) {
        BREAKPOINT();
    }
    // TODO check if event is already exists and return it. Currently we just add in m_events array
    m_events.push_back(event);

    if (event.isTriggered) {
        BREAKPOINT(); // we don't support that either yet
    }

    return 0;
}

int EqueueInternal::waitForEvents(SceKernelEvent* ev, int num, u32 micros) {
    std::unique_lock lock{m_mutex};
    int ret = 0;

    const auto predicate = [&] {
        ret = getTriggeredEvents(ev, num);
        return ret > 0;
    };

    if (micros == 0) {
        m_cond.wait(lock, predicate);
    } else {
        m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate);
    }
    return ret;
}

bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
    std::scoped_lock lock{m_mutex};

    if (m_events.size() > 1) {
        BREAKPOINT(); // we currently support one event
    }
    auto& event = m_events[0];

    if (event.filter.trigger_event_func != nullptr) {
        event.filter.trigger_event_func(&event, trigger_data);
    } else {
        event.isTriggered = true;
    }

    m_cond.notify_one();

    return true;
}

int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
    int ret = 0;

    if (m_events.size() > 1) {
        BREAKPOINT(); // we currently support one event
    }
    auto& event = m_events[0];

    if (event.isTriggered) {
        ev[ret++] = event.event;

        if (event.filter.reset_event_func != nullptr) {
            event.filter.reset_event_func(&event);
        }
    }

    return ret;
}

} // namespace Core::Kernel
