/*
 * SPDX-FileCopyrightText: 2025 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
#ifndef TANGO_INTERNAL_CLIENT_EVENT_HELPERS_H
#define TANGO_INTERNAL_CLIENT_EVENT_HELPERS_H

#include <tango/internal/utils.h>

#include <tango/client/ApiUtil.h>
#include <tango/client/CallBack.h>
#include <tango/client/EventQueue.h>
#include <tango/common/tango_const.h>
#include <tango/common/utils/assert.h>

#include <string>

namespace Tango
{

inline bool ensure_failure_reason_with_errors(Tango::EventReason event_reason, const Tango::DevFailed &e)
{
    switch(event_reason)
    {
    case Tango::EventReason::SubFail:
        return e.errors.length() > 0;
    case Tango::EventReason::SubSuccess:
        [[fallthrough]];
    case Tango::EventReason::Update:
        // no distinction
        return true;
    case Tango::EventReason::Unknown:
        // we don't allow explicitly setting Unknown
        return false;
    default:
        TANGO_ASSERT_ON_DEFAULT(event_reason);
        return false;
    }
}

//--------------------------------------------------------------------------------------------------------------------
//
// tries to execute user callback if specified and printout error, if failed, otherwise stores data in the event queue
//
//--------------------------------------------------------------------------------------------------------------------
template <typename T>
void safe_execute_callback_or_store_data(Tango::CallBack *callback,
                                         T *event_data,
                                         bool err_missed_event,
                                         T *missed_data,
                                         const std::string &method_name,
                                         const std::string &event_name,
                                         Tango::EventQueue *ev_queue)
{
    // if callback methods were specified, call them!
    if(callback != nullptr)
    {
        try
        {
            if(err_missed_event)
            {
                callback->push_event(missed_data);
            }
            callback->push_event(event_data);
        }
        catch(const Tango::DevFailed &e)
        {
            Tango::ApiUtil *au = Tango::ApiUtil::instance();
            std::stringstream ss;
            ss << method_name << " got DevFailed exception: \n\n";
            ss << e.errors[0].desc;
            ss << "\nin callback method of: ";
            ss << event_name;
            au->print_error_message(ss.str().c_str());
        }
        catch(const std::exception &e)
        {
            Tango::ApiUtil *au = Tango::ApiUtil::instance();
            std::stringstream ss;
            ss << method_name << " got std::exception: \n\n";
            ss << e.what();
            ss << "\nin callback method of: ";
            ss << event_name;
            au->print_error_message(ss.str().c_str());
        }
        catch(...)
        {
            Tango::ApiUtil *au = Tango::ApiUtil::instance();
            std::stringstream ss;
            ss << method_name << " got unknown exception\n\n";
            ss << "in callback method of: ";
            ss << event_name;
            au->print_error_message(ss.str().c_str());
        }
        delete event_data;
    }

    // no callback method, the event has to be inserted
    // into the event queue
    else
    {
        if(err_missed_event)
        {
            auto *missed_data_copy = new T(*missed_data);
            ev_queue->insert_event(missed_data_copy);
        }
        ev_queue->insert_event(event_data);
    }
}

// overload for calls without missed event
template <typename T>
void safe_execute_callback_or_store_data(CallBack *callback,
                                         T *event_data,
                                         const std::string &method_name,
                                         const std::string &event_name,
                                         EventQueue *ev_queue)
{
    safe_execute_callback_or_store_data(
        callback, event_data, false, static_cast<T *>(nullptr), method_name, event_name, ev_queue);
}

} // namespace Tango
#endif // TANGO_INTERNAL_CLIENT_EVENT_HELPERS_H
