/*
 * Copyright 2025 Rive
 */

#pragma once

#include "rive/command_queue.hpp"
#include "rive/hit_result.hpp"
#include "rive/math/mat2d.hpp"
#include <iostream>
#include <sstream>
#include <thread>
#include <unordered_map>
#include <type_traits>

namespace rive
{
class ScriptingContext;
class GlobalAssetRegistry;

// Server-side worker that executes commands from a CommandQueue.
class CommandServer
{
public:
    /**
     * Creates the server that executes commands from commandQueue.
     *
     * @param commandQueue The queue from which commands are read.
     * @param factory The factory used to create runtime resources.
     * @param internalFileAssetLoader An optional FileAssetLoader for loading
     * out-of-band asset contents without using command-queue global assets.
     * Provide a loader that recognizes and loads the assets it owns, returning
     * true from FileAssetLoader::loadContents for those assets. This is
     * typically used by an embedder that already has its own asset-loading
     * path. Leave it null when out-of-band images, audio, and fonts should be
     * handled through the command queue.
     */
    CommandServer(rcp<CommandQueue> commandQueue,
                  Factory* factory,
                  rcp<rive::FileAssetLoader> internalFileAssetLoader = nullptr);
    virtual ~CommandServer();

    Factory* factory() const { return m_factory; }

    rive::HitResult pointerDownSynchronized(StateMachineHandle,
                                            const CommandQueue::PointerEvent&);
    rive::HitResult pointerMoveSynchronized(StateMachineHandle,
                                            const CommandQueue::PointerEvent&);
    rive::HitResult pointerUpSynchronized(StateMachineHandle,
                                          const CommandQueue::PointerEvent&);

    File* getFile(FileHandle) const;
    bool getWasDisconnected() const { return m_wasDisconnectReceived; }
    RenderImage* getImage(RenderImageHandle) const;
    AudioSource* getAudioSource(AudioSourceHandle) const;
    Font* getFont(FontHandle) const;
    BlobAsset* getBlob(BlobAssetHandle) const;
    ArtboardInstance* getArtboardInstance(ArtboardHandle) const;
    rcp<BindableArtboard> getBindableArtboard(ArtboardHandle) const;
    StateMachineInstance* getStateMachineInstance(StateMachineHandle) const;
    ViewModelInstanceRuntime* getViewModelInstance(
        ViewModelInstanceHandle) const;
    ViewModelInstanceHandle getHandleForInstance(
        ViewModelInstanceRuntime*) const;
    // Wait for queue to not be empty, then returns pollMessages.
    bool waitCommands();
    // Returns immediately after checking messages. If there are none just
    // returns !m_wasDisconnectReceived.
    bool processCommands();
    // Blocks and runs waitMessages until disconnect is received.
    void serveUntilDisconnect();

    /**
     * Posts a runtime-defined message to the command queue.
     *
     * This is intended for host runtime integrations that need to report
     * information discovered while executing command server work, such as from
     * runOnce or draw callbacks. The command queue forwards the message through
     * its RuntimeMessageListener when processMessages() runs. Rive does not
     * interpret the tag or payload.
     *
     * @param tag Runtime-owned message type identifier.
     * @param payload Runtime-owned serialized message bytes.
     */
    void postRuntimeMessage(uint32_t tag, std::vector<uint8_t> payload);

    struct Subscription
    {
        // The request Id for subscribing to this particular property.
        uint64_t requestId;
        // Information about the property we want to "subscribe" to.
        PropertyData data;
        // The root view model from the perspective of the path in data.name.
        ViewModelInstanceHandle rootViewModel;
    };

#ifdef TESTING
    // Expose cursorPosForPointerEvent for testing.
    Vec2D testing_cursorPosForPointerEvent(StateMachineInstance* instance,
                                           CommandQueue::PointerEvent event)
    {
        return cursorPosForPointerEvent(instance, event);
    }

    const std::vector<Subscription>& testing_getSubscriptions() const
    {
        return m_propertySubscriptions;
    }

    RenderImageHandle testing_globalImageNamed(std::string name);
    AudioSourceHandle testing_globalAudioNamed(std::string name);
    FontHandle testing_globalFontNamed(std::string name);

    bool testing_globalImageContains(std::string name);
    bool testing_globalAudioContains(std::string name);
    bool testing_globalFontContains(std::string name);

#ifndef NDEBUG
    // Used because "sync pointer events" test needs to be able to
    // make the server on one thread but access it from another
    void testing_overrideThreadID(std::thread::id threadID)
    {
        m_threadID = threadID;
    }
#endif
#endif

    bool focusNextSynchronized(StateMachineHandle);
    bool focusPreviousSynchronized(StateMachineHandle);

private:
    friend class CommandQueue;

    template <typename HandleType> class ErrorReporter
    {
    public:
        ErrorReporter(CommandServer* server,
                      HandleType handle,
                      uint64_t requestId,
                      CommandQueue::Message message) :
            m_server(server), m_lock(m_server->m_commandQueue->m_messageMutex)
        {
            assert(server);
            assert(message >= CommandQueue::Message::fileError &&
                   message <= CommandQueue::Message::stateMachineError);

            std::cerr << "ERROR : ";
            m_server->m_commandQueue->m_messageStream << message;
            m_server->m_commandQueue->m_messageStream << handle;
            m_server->m_commandQueue->m_messageStream << requestId;
        }

        ErrorReporter& operator<<(std::vector<std::string> vector)
        {
            m_ostringstream << "{ ";
            for (auto& s : vector)
                m_ostringstream << s << ",";
            m_ostringstream << "} ";
            return *this;
        }

        template <typename T> ErrorReporter& operator<<(const T& t)
        {
            m_ostringstream << t;
            return *this;
        }

        ~ErrorReporter()
        {
            std::string str = m_ostringstream.str();
            assert(!str.empty());
            std::cerr << str << "\n";
            m_server->m_commandQueue->m_messageNames << std::move(str);
        }

        CommandServer* m_server;
        std::unique_lock<std::mutex> m_lock;
        std::ostringstream m_ostringstream;
    };

    void checkPropertySubscriptions();

    Vec2D cursorPosForPointerEvent(StateMachineInstance*,
                                   const CommandQueue::PointerEvent&);

    void cleanupArtboard(ArtboardHandle handle, uint64_t requestId)
    {
        auto itr = m_artboards.find(handle);
        if (itr != m_artboards.end())
        {
            auto dependencyItr = m_artboardDependencies.find(handle);
            if (dependencyItr != m_artboardDependencies.end())
            {
                auto& stateMachineVector = dependencyItr->second;
                for (auto stateMachine : stateMachineVector)
                {
                    if (m_stateMachines.erase(stateMachine) > 0)
                    {
                        std::unique_lock<std::mutex> lock(
                            m_commandQueue->m_messageMutex);
                        m_commandQueue->m_messageStream
                            << CommandQueue::Message::stateMachineDeleted;
                        m_commandQueue->m_messageStream << stateMachine;
                        m_commandQueue->m_messageStream << requestId;
                    }
                }

                m_artboardDependencies.erase(dependencyItr);
            }
            m_artboards.erase(itr);
            std::unique_lock<std::mutex> lock(m_commandQueue->m_messageMutex);
            m_commandQueue->m_messageStream
                << CommandQueue::Message::artboardDeleted;
            m_commandQueue->m_messageStream << handle;
            m_commandQueue->m_messageStream << requestId;
        }
    }

    struct SynchronizedStateMachine : RefCnt<SynchronizedStateMachine>
    {
        // Kept out of line to avoid including StateMachineInstance in the main
        // CommandServer header.
        ~SynchronizedStateMachine();
        SynchronizedStateMachine& operator=(SynchronizedStateMachine&& other);
        SynchronizedStateMachine() = default;
        SynchronizedStateMachine(
            std::unique_ptr<StateMachineInstance> instance);
        std::unique_ptr<StateMachineInstance> instance;
        Mat2D m_lastSemanticsTransform;
        bool m_hasLastSemanticsTransform = false;
        // This mutex ensures that a specific state machine instance is not
        // advanced while a synchronized input or focus operation is running.
        std::mutex m_mutex;
    };

    rcp<CommandServer::SynchronizedStateMachine> getStateMachineWrapper(
        StateMachineHandle handle);

    bool m_wasDisconnectReceived = false;
    const rcp<CommandQueue> m_commandQueue;
    Factory* const m_factory;
#ifndef NDEBUG
#ifdef TESTING
    std::thread::id m_threadID;
#else
    const std::thread::id m_threadID;
#endif
#endif

    // Vector to iterate on for subscriptions. This is a vector instead of a map
    // because we iterate through the entire vector every frame anyway.
    std::vector<Subscription> m_propertySubscriptions;

    // Dependencies
    // When a file gets deleted artboards and state machines become invalid.
    // Here we hold a reference to the artboard only because that artboard has a
    // dependency to the State Machine.
    std::unordered_map<FileHandle, std::vector<ArtboardHandle>>
        m_fileDependencies;
    // When an artboard gets deleted the state machine associated with it is
    // also now invalid.
    std::unordered_map<ArtboardHandle, std::vector<StateMachineHandle>>
        m_artboardDependencies;

    // Handle Maps
    std::unordered_map<FileHandle, rcp<File>> m_files;
    std::unordered_map<FontHandle, rcp<Font>> m_fonts;
    std::unordered_map<RenderImageHandle, rcp<RenderImage>> m_images;
    std::unordered_map<BlobAssetHandle, rcp<BlobAsset>> m_blobs;
    std::unordered_map<AudioSourceHandle, rcp<AudioSource>> m_audioSources;
    std::unordered_map<ArtboardHandle, rcp<BindableArtboard>> m_artboards;
    std::unordered_map<ViewModelInstanceHandle, rcp<ViewModelInstanceRuntime>>
        m_viewModels;
    std::unordered_map<StateMachineHandle, rcp<SynchronizedStateMachine>>
        m_stateMachines;
    std::mutex m_stateMachineAccessMutex;

    std::unordered_map<DrawKey, CommandServerDrawCallback> m_uniqueDraws;

    class CommandFileAssetLoader;
    rcp<GlobalAssetRegistry> m_globalAssetRegistry;
    rcp<FileAssetLoader> m_internalFileAssetLoader;
};
}; // namespace rive
