#pragma once
#include <memory>
#include <vector>
#include <shared_mutex>
#include "../protocol/protocol.hpp"
#include "../provider/base/provider_interface.hpp"

namespace lsp::core
{

    using ServerLifecycleEvent = providers::ServerLifecycleEvent;
    using LifecycleCallback = providers::LifecycleCallback;

    class RequestDispatcher
    {
    public:
        RequestDispatcher() = default;
        ~RequestDispatcher() = default;

        void SetRequestScheduler(scheduler::RequestScheduler* scheduler);

        void RegisterRequestProvider(std::shared_ptr<providers::IRequestProvider> provider);
        void RegisterNotificationProvider(std::shared_ptr<providers::INotificationProvider> provider);

        void RegisterLifecycleCallback(LifecycleCallback callback);

        std::string Dispatch(const protocol::RequestMessage& request);
        void Dispatch(const protocol::NotificationMessage& notification);

        bool SupportsRequest(const std::string& method) const;
        bool SupportsNotification(const std::string& method) const;
        std::vector<std::string> GetSupportedRequests() const;
        std::vector<std::string> GetSupportedNotifications() const;
        std::vector<std::string> GetAllSupportedMethods() const;

        std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);

    private:
        void NotifyAllLifecycleListeners(ServerLifecycleEvent event);
        std::string HandleUnknownRequest(const protocol::RequestMessage& request);
        void HandleUnknownNotification(const protocol::NotificationMessage& notification);

    private:
        mutable std::shared_mutex providers_mutex_;
        std::unordered_map<std::string, std::shared_ptr<providers::IRequestProvider>> providers_;

        mutable std::shared_mutex notification_providers_mutex_;
        std::unordered_map<std::string, std::shared_ptr<providers::INotificationProvider>> notification_providers_;

        std::mutex callbacks_mutex_;
        std::vector<LifecycleCallback> lifecycle_callbacks_;

        scheduler::RequestScheduler* scheduler_ = nullptr;
    };

}
