#include "kernel.h"
#include "egl_context.h"
#include "render_target.h"
#include <mosis/util/logger.h>
#include "assets_manager.h"
#include "apps/app_manager.h"
#include "apps/update_service.h"
#include "apps/app_api.h"
#include "sandbox/sandbox_manager.h"
#include "aidl/com/omixlab/mosis/IMosisListener.h"
#include <android/hardware_buffer.h>
#include <android/asset_manager.h>
#include <RmlUi/Core.h>
#include <RmlUi/Lua.h>
#include <RmlUi/Lua/Interpreter.h>
#include <RmlUi/Lua/LuaType.h>
#include "RmlUi_Renderer_GL3.h"
#include <span>
#include <ranges>
#include <chrono>
#include <format>
#include <fstream>
#include <sstream>
#include <filesystem>

// Sandbox API includes for RmlUi integration
#include <mosis/sandbox/timer_manager.h>
#include <mosis/sandbox/json_api.h>
#include <mosis/sandbox/crypto_api.h>
#include <mosis/sandbox/virtual_fs.h>

// External function to get files directory from JNI
extern const std::string& GetFilesDir();

// Global state for Lua access
static Rml::Context* g_context = nullptr;
static Rml::ElementDocument* g_document = nullptr;
static mosis::AppManager* g_app_manager = nullptr;
static mosis::UpdateService* g_update_service = nullptr;
static mosis::LuaSandboxManager* g_sandbox_manager = nullptr;

// RmlUi sandbox state - APIs registered into RmlUi's Lua state
static std::unique_ptr<mosis::TimerManager> g_rmlui_timer_manager;
static std::unique_ptr<mosis::VirtualFS> g_rmlui_vfs;
static std::string g_current_app_id = "com.mosis.home";
static std::string g_data_root;

// Forward declarations
static void SwitchAppSandbox(const std::string& app_id, const std::string& app_data_path);

// Helper to set the 'document' global in Lua to the current document
// This is needed for external script files (app.lua) that reference 'document'
static void SetLuaDocumentGlobal(Rml::ElementDocument* doc) {
    if (!doc) return;
    lua_State* L = Rml::Lua::Interpreter::GetLuaState();
    if (!L) return;

    // Push the document using RmlUi's Lua type system
    Rml::Lua::LuaType<Rml::ElementDocument>::push(L, doc, false);
    lua_setglobal(L, "document");
    Logger::Log(std::format("Set Lua 'document' global to: {}", doc->GetTitle().empty() ? "(untitled)" : doc->GetTitle().c_str()));
}

using namespace aidl::com::omixlab::mosis;
using namespace aidl::android::hardware;

// File handle wrapper to support both assets and filesystem files
struct FileHandleWrapper {
    enum class Type { Asset, File };
    Type type;
    union {
        AAsset* asset;
        std::ifstream* file;
    };
    size_t file_size = 0;  // For filesystem files
};

class AssetFilesInterface : public Rml::FileInterface
{
    // Track base path of currently loading document for relative path resolution
    std::string m_current_document_base;

public:
    static AssetFilesInterface& Instance()
    {
        static AssetFilesInterface instance;
        return instance;
    }

    // Set the base path for relative resource resolution (called before LoadDocument)
    void SetDocumentBasePath(const std::string& doc_path) {
        // Extract directory from full document path
        size_t last_slash = doc_path.find_last_of("/\\");
        if (last_slash != std::string::npos) {
            m_current_document_base = doc_path.substr(0, last_slash + 1);
        } else {
            m_current_document_base = "";
        }
        Logger::Log(std::format("Document base path set to: {}", m_current_document_base));
    }

    void ClearDocumentBasePath() {
        m_current_document_base = "";
    }

    // Check if path is a filesystem path (starts with / or file://)
    static bool IsFilesystemPath(const Rml::String& path) {
        return !path.empty() && (path[0] == '/' || path.rfind("file://", 0) == 0);
    }

    // Get the actual filesystem path, stripping file:// prefix if present
    static Rml::String GetFilesystemPath(const Rml::String& path) {
        if (path.rfind("file://", 0) == 0) {
            return path.substr(7);  // Strip "file://"
        }
        return path;
    }

    // Resolve a path - if it's relative and we have a filesystem base, resolve against it
    Rml::String ResolvePath(const Rml::String& path) const {
        // If already absolute or explicitly a filesystem/asset path, return as-is
        if (IsFilesystemPath(path)) {
            return path;
        }

        // If we have a filesystem base path and this is a relative path, resolve it
        if (!m_current_document_base.empty() && IsFilesystemPath(m_current_document_base)) {
            Rml::String resolved = m_current_document_base + path;
            Logger::Log(std::format("Resolved relative path '{}' to '{}'", path, resolved));
            return resolved;
        }

        // Otherwise, treat as asset path
        return path;
    }

    Rml::FileHandle Open(const Rml::String &path) override
    {
        // Resolve relative paths against current document base
        Rml::String resolved_path = ResolvePath(path);

        auto* wrapper = new FileHandleWrapper();

        if (IsFilesystemPath(resolved_path)) {
            // Filesystem path
            Rml::String fs_path = GetFilesystemPath(resolved_path);
            auto* file = new std::ifstream(fs_path, std::ios::binary);
            if (!file->is_open()) {
                Logger::Log(std::format("Open failed for filesystem: {}", fs_path));
                delete file;
                delete wrapper;
                return 0;
            }
            file->seekg(0, std::ios::end);
            wrapper->file_size = file->tellg();
            file->seekg(0, std::ios::beg);
            wrapper->type = FileHandleWrapper::Type::File;
            wrapper->file = file;
        } else {
            // Asset path
            AAssetManager* am = AssetsManager::Native();
            AAsset* asset = AAssetManager_open(am, resolved_path.c_str(), AASSET_MODE_BUFFER);
            if (!asset) {
                Logger::Log(std::format("Open failed for asset: {}", resolved_path));
                delete wrapper;
                return 0;
            }
            wrapper->type = FileHandleWrapper::Type::Asset;
            wrapper->asset = asset;
        }

        return reinterpret_cast<Rml::FileHandle>(wrapper);
    }

    void Close(Rml::FileHandle file) override
    {
        auto* wrapper = reinterpret_cast<FileHandleWrapper*>(file);
        if (!wrapper) return;

        if (wrapper->type == FileHandleWrapper::Type::Asset) {
            AAsset_close(wrapper->asset);
        } else {
            wrapper->file->close();
            delete wrapper->file;
        }
        delete wrapper;
    }

    size_t Read(void *buffer, size_t size, Rml::FileHandle file) override
    {
        auto* wrapper = reinterpret_cast<FileHandleWrapper*>(file);
        if (!wrapper) return 0;

        if (wrapper->type == FileHandleWrapper::Type::Asset) {
            return AAsset_read(wrapper->asset, buffer, size);
        } else {
            wrapper->file->read(static_cast<char*>(buffer), size);
            return wrapper->file->gcount();
        }
    }

    bool Seek(Rml::FileHandle file, long offset, int origin) override
    {
        auto* wrapper = reinterpret_cast<FileHandleWrapper*>(file);
        if (!wrapper) return false;

        if (wrapper->type == FileHandleWrapper::Type::Asset) {
            off_t new_cursor = AAsset_seek(wrapper->asset, offset, origin);
            return new_cursor != -1;
        } else {
            std::ios_base::seekdir dir = std::ios::beg;
            if (origin == SEEK_CUR) dir = std::ios::cur;
            else if (origin == SEEK_END) dir = std::ios::end;
            wrapper->file->seekg(offset, dir);
            return !wrapper->file->fail();
        }
    }

    size_t Tell(Rml::FileHandle file) override
    {
        auto* wrapper = reinterpret_cast<FileHandleWrapper*>(file);
        if (!wrapper) return 0;

        if (wrapper->type == FileHandleWrapper::Type::Asset) {
            return AAsset_seek(wrapper->asset, 0, SEEK_CUR);
        } else {
            return wrapper->file->tellg();
        }
    }

    size_t Length(Rml::FileHandle file) override
    {
        auto* wrapper = reinterpret_cast<FileHandleWrapper*>(file);
        if (!wrapper) return 0;

        if (wrapper->type == FileHandleWrapper::Type::Asset) {
            return AAsset_getLength(wrapper->asset);
        } else {
            return wrapper->file_size;
        }
    }

    bool LoadFile(const Rml::String &path, Rml::String &out_data) override
    {
        Logger::Log(std::format("LoadFile requested: {}", path));

        // Resolve relative paths against current document base
        Rml::String resolved_path = ResolvePath(path);

        if (IsFilesystemPath(resolved_path)) {
            // Load from filesystem
            Rml::String fs_path = GetFilesystemPath(resolved_path);
            Logger::Log(std::format("  -> Loading from filesystem: {}", fs_path));
            std::ifstream file(fs_path, std::ios::binary | std::ios::ate);
            if (!file.is_open()) {
                Logger::Log(std::format("  -> FAILED to open file: {}", fs_path));
                return false;
            }

            size_t size = file.tellg();
            file.seekg(0, std::ios::beg);
            out_data.resize(size);
            file.read(out_data.data(), size);
            Logger::Log(std::format("  -> Loaded {} bytes from filesystem", size));
            return true;
        } else {
            // Load from assets
            Logger::Log(std::format("  -> Loading from assets: {}", resolved_path));
            AAssetManager* am = AssetsManager::Native();
            AAsset* asset = AAssetManager_open(am, resolved_path.c_str(), AASSET_MODE_BUFFER);
            if (!asset) {
                Logger::Log(std::format("  -> FAILED to load from assets: {}", resolved_path));
                return false;
            }

            out_data.resize(AAsset_getLength(asset));
            auto data_ptr = static_cast<const char*>(AAsset_getBuffer(asset));
            std::span data = std::span(data_ptr, out_data.size());
            std::ranges::copy(data, out_data.begin());
            AAsset_close(asset);
            Logger::Log(std::format("  -> Loaded {} bytes from assets", out_data.size()));
            return true;
        }
    }
};

class SystemInterface : public Rml::SystemInterface
{
public:
    static SystemInterface& Instance()
    {
        static SystemInterface instance;
        return instance;
    }
    bool LogMessage(Rml::Log::Type type, const Rml::String &message) override
    {
        Logger::Log(std::format("RMLUI: {}", message));
        return true;
    }
};

// Lua function to load a screen document
static int LuaLoadScreen(lua_State* L)
{
    if (!g_context)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    const char* path = luaL_checkstring(L, 1);
    Logger::Log(std::format("Loading screen: {}", path));

    // Check if file exists - support both asset and filesystem paths
    bool exists = false;
    if (AssetFilesInterface::IsFilesystemPath(path)) {
        // Filesystem path
        exists = std::filesystem::exists(path);
    } else {
        // Asset path
        AAssetManager* am = AssetsManager::Native();
        AAsset* asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER);
        if (asset) {
            exists = true;
            AAsset_close(asset);
        }
    }

    if (!exists)
    {
        Logger::Log(std::format("Screen not found: {}", path));
        lua_pushboolean(L, false);
        return 1;
    }

    // Set document base path for relative resource resolution (scripts, stylesheets)
    // This is crucial for filesystem documents to load their scripts correctly
    AssetFilesInterface::Instance().SetDocumentBasePath(path);

    // Unload current document
    if (g_document)
    {
        g_context->UnloadDocument(g_document);
        g_document = nullptr;
    }

    // Load new document
    g_document = g_context->LoadDocument(path);
    if (g_document)
    {
        g_document->Show();
        SetLuaDocumentGlobal(g_document);
        Logger::Log(std::format("Loaded screen: {}", path));
        lua_pushboolean(L, true);
    }
    else
    {
        Logger::Log(std::format("Failed to load screen: {}", path));
        lua_pushboolean(L, false);
    }

    // Clear base path after document is fully loaded
    AssetFilesInterface::Instance().ClearDocumentBasePath();

    return 1;
}

// Lua function to go back to home screen
static int LuaGoHome(lua_State* L)
{
    if (!g_context)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    Logger::Log("goHome called - returning to home screen");

    // Stop any running third-party app in the legacy sandbox manager
    if (g_sandbox_manager) {
        auto running_apps = g_sandbox_manager->GetRunningApps();
        for (const auto& app_id : running_apps) {
            // Don't stop system apps
            if (app_id.find("com.mosis.") == 0 && app_id != "com.mosis.home") {
                Logger::Log(std::format("Stopping app: {}", app_id));
                g_sandbox_manager->StopApp(app_id);
            }
        }
    }

    // Switch sandbox context back to home screen
    SwitchAppSandbox("com.mosis.home", g_data_root);

    // Load shell (which shows home by default)
    const char* home_path = "apps/shell/shell.rml";

    // Unload current document
    if (g_document)
    {
        g_context->UnloadDocument(g_document);
        g_document = nullptr;
    }

    // Load home document
    g_document = g_context->LoadDocument(home_path);
    if (g_document)
    {
        g_document->Show();
        SetLuaDocumentGlobal(g_document);
        Logger::Log("Returned to home screen");
        lua_pushboolean(L, true);
    }
    else
    {
        Logger::Log("Failed to load home screen");
        lua_pushboolean(L, false);
    }

    return 1;
}

// Register sandbox APIs (timer, json, crypto, fs) into RmlUi's Lua state
static void RegisterSandboxAPIs(lua_State* L)
{
    Logger::Log("Registering sandbox APIs...");

    // Register timer API
    if (g_rmlui_timer_manager) {
        mosis::RegisterTimerAPI(L, g_rmlui_timer_manager.get(), g_current_app_id);
        Logger::Log("  Timer API registered");
    }

    // Register JSON API
    mosis::RegisterJsonAPI(L, mosis::JsonLimits{});
    Logger::Log("  JSON API registered");

    // Register crypto API
    mosis::RegisterCryptoAPI(L);
    Logger::Log("  Crypto API registered");

    // Register virtual filesystem API
    if (g_rmlui_vfs) {
        mosis::RegisterVirtualFS(L, g_rmlui_vfs.get());
        Logger::Log("  VirtualFS API registered");
    }

    Logger::Log("All sandbox APIs registered");
}

// Unregister sandbox APIs (for clean switch between apps)
static void UnregisterSandboxAPIs(lua_State* L)
{
    // Clear timer globals
    lua_pushnil(L);
    lua_setglobal(L, "setTimeout");
    lua_pushnil(L);
    lua_setglobal(L, "clearTimeout");
    lua_pushnil(L);
    lua_setglobal(L, "setInterval");
    lua_pushnil(L);
    lua_setglobal(L, "clearInterval");

    // Clear json global
    lua_pushnil(L);
    lua_setglobal(L, "json");

    // Clear crypto global
    lua_pushnil(L);
    lua_setglobal(L, "crypto");

    // Clear fs global
    lua_pushnil(L);
    lua_setglobal(L, "fs");

    Logger::Log("Sandbox APIs unregistered");
}

// Switch sandbox context to a different app
static void SwitchAppSandbox(const std::string& app_id, const std::string& app_data_path)
{
    lua_State* L = Rml::Lua::Interpreter::GetLuaState();

    // Clear timers for current app
    if (g_rmlui_timer_manager) {
        g_rmlui_timer_manager->ClearAppTimers(g_current_app_id);
        Logger::Log(std::format("Timers cleared for {}", g_current_app_id));
    }

    // Unregister current APIs
    UnregisterSandboxAPIs(L);

    // Update current app ID
    g_current_app_id = app_id;

    // Create new VirtualFS for the app
    std::string vfs_path = app_data_path.empty() ?
        (g_data_root + "/sandbox_data") :
        (app_data_path + "/sandbox_data");

    std::filesystem::create_directories(vfs_path);

    g_rmlui_vfs = std::make_unique<mosis::VirtualFS>(
        app_id,
        vfs_path,
        mosis::VirtualFSLimits{}
    );

    Logger::Log(std::format("VirtualFS created for {} at {}", app_id, vfs_path));

    // Register APIs for new app
    RegisterSandboxAPIs(L);
}

// Lua function to switch sandbox context for a third-party app
// Called before loading an app's UI: switchAppSandbox(app_id, install_path)
static int LuaSwitchAppSandbox(lua_State* L)
{
    const char* app_id = luaL_checkstring(L, 1);
    const char* install_path = luaL_checkstring(L, 2);

    Logger::Log(std::format("Switching sandbox to app: {} at {}", app_id, install_path));

    SwitchAppSandbox(app_id, install_path);

    lua_pushboolean(L, true);
    return 1;
}

// Load app content fragment into a container element
static int LuaLoadAppContent(lua_State* L)
{
    // Get element from first argument
    Rml::Element* element = Rml::Lua::LuaType<Rml::Element>::check(L, 1);
    if (!element) {
        Logger::Log("loadAppContent: Invalid element argument");
        lua_pushboolean(L, false);
        return 1;
    }

    // Get path from second argument
    const char* path = luaL_checkstring(L, 2);
    Logger::Log(std::format("loadAppContent: Loading {} into element", path));

    // Read file content - try assets first, then filesystem
    std::string content;
    AAssetManager* am = AssetsManager::Native();
    AAsset* asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER);

    if (asset) {
        // Load from assets
        size_t length = AAsset_getLength(asset);
        const char* data = static_cast<const char*>(AAsset_getBuffer(asset));
        content = std::string(data, length);
        AAsset_close(asset);
        Logger::Log(std::format("  -> Loaded {} bytes from assets", length));
    } else {
        // Try filesystem (for installed apps)
        std::string fs_path = GetFilesDir() + "/" + path;
        std::ifstream file(fs_path);
        if (file.is_open()) {
            std::stringstream buffer;
            buffer << file.rdbuf();
            content = buffer.str();
            Logger::Log(std::format("  -> Loaded {} bytes from filesystem", content.size()));
        } else {
            Logger::Log(std::format("loadAppContent: Cannot open file: {}", path));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    // Set inner RML
    element->SetInnerRML(content);
    Logger::Log("loadAppContent: Content loaded successfully");

    lua_pushboolean(L, true);
    return 1;
}

// Register Lua functions for navigation
static void RegisterLuaFunctions(const std::string& current_app_id, bool is_system_app)
{
    lua_State* L = Rml::Lua::Interpreter::GetLuaState();
    lua_pushcfunction(L, LuaLoadScreen);
    lua_setglobal(L, "loadScreen");
    lua_pushcfunction(L, LuaGoHome);
    lua_setglobal(L, "goHome");
    lua_pushcfunction(L, LuaSwitchAppSandbox);
    lua_setglobal(L, "switchAppSandbox");
    lua_pushcfunction(L, LuaLoadAppContent);
    lua_setglobal(L, "loadAppContent");
    Logger::Log("Registered Lua loadScreen, goHome, switchAppSandbox, and loadAppContent functions");

    // Register app management APIs
    if (g_app_manager && g_update_service) {
        mosis::RegisterAppAPIs(L, g_app_manager, g_update_service, current_app_id, is_system_app);
        Logger::Log("Registered Lua app management APIs");
    }

    // Initialize and register sandbox APIs
    RegisterSandboxAPIs(L);
}

void Kernel::main_loop()
{
    m_egl_context = std::make_unique<egl::Context>();
    if (!m_egl_context->create())
    {
        Logger::Log("failed to create EGL context");
        return;
    }
    m_render_target = std::make_unique<RenderTarget>();
    if (!m_render_target->create_exported(540, 960))
    {
        Logger::Log("failed to create render target");
        return;
    }
    m_render_target->bind();
    for (const auto& [pid, l] : m_listeners)
        l->onServiceInitialized(true);
    m_aidl_buffer = std::make_unique<HardwareBuffer>();
    m_aidl_buffer->reset(m_render_target->hardware_buffer());
    for (const auto& [pid, l] : m_listeners)
        l->onBufferAvailable(*m_aidl_buffer);

    RenderInterface_GL3 rmlui_render_interface;
    if (!rmlui_render_interface)
    {
        Logger::Log("failed to create render interface");
        return;
    }
    Rml::SetRenderInterface(&rmlui_render_interface);
    Rml::SetFileInterface(&AssetFilesInterface::Instance());
    Rml::SetSystemInterface(&SystemInterface::Instance());
    Rml::Initialise();
    Rml::Lua::Initialise();
    Logger::Log("RmlUi Lua bindings initialized");

    // Initialize app management system
    // Get files directory from Android context (set via JNI)
    std::string data_root = GetFilesDir();
    if (data_root.empty()) {
        // Fallback if not set (shouldn't happen in normal operation)
        data_root = "/data/data/com.omixlab.mosis/files";
        Logger::Log("Warning: Files directory not set, using fallback");
    }
    g_data_root = data_root;  // Store for sandbox switching
    Logger::Log("Using data root: " + data_root);
    m_app_manager = std::make_unique<mosis::AppManager>(data_root);
    m_update_service = std::make_unique<mosis::UpdateService>(
        m_app_manager.get(), "https://portal.mosis.dev/api/v1");
    m_sandbox_manager = std::make_unique<mosis::LuaSandboxManager>(data_root);
    m_app_manager->SetSandboxManager(m_sandbox_manager.get());
    g_app_manager = m_app_manager.get();
    g_update_service = m_update_service.get();
    g_sandbox_manager = m_sandbox_manager.get();
    Logger::Log("App management system initialized");

    // Initialize RmlUi sandbox state (timer manager and VFS for home screen)
    g_rmlui_timer_manager = std::make_unique<mosis::TimerManager>();
    std::string home_sandbox_path = data_root + "/sandbox_data";
    std::filesystem::create_directories(home_sandbox_path);
    g_rmlui_vfs = std::make_unique<mosis::VirtualFS>(
        "com.mosis.home", home_sandbox_path, mosis::VirtualFSLimits{});
    Logger::Log("RmlUi sandbox initialized");

    // Start background update checks (every 24 hours)
    m_update_service->Start(std::chrono::hours(24));

    // Register navigation functions with Lua
    // Home screen is a system app with full access
    RegisterLuaFunctions("com.mosis.home", true);

    g_context = Rml::CreateContext("default", Rml::Vector2i(540, 960));
    if (!g_context)
    {
        Logger::Log("RMLUI failed to create a context");
        Rml::Shutdown();
        return;
    }
    // Load fonts from assets/fonts/
    Rml::LoadFontFace("fonts/LatoLatin-Bold.ttf");
    Rml::LoadFontFace("fonts/LatoLatin-BoldItalic.ttf");
    Rml::LoadFontFace("fonts/LatoLatin-Italic.ttf");
    Rml::LoadFontFace("fonts/LatoLatin-Regular.ttf");
    Rml::LoadFontFace("fonts/NotoEmoji-Regular.ttf", true);
    Rml::LoadFontFace("fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf");
    Rml::LoadFontFace("fonts/Roboto/Roboto-Italic-VariableFont_wdth,wght.ttf");

    // Load shell document (provides persistent status bar, nav bar, and loads home content)
    g_document = g_context->LoadDocument("apps/shell/shell.rml");
    if (!g_document)
    {
        Logger::Log("Failed to load shell.rml document");
        Rml::Shutdown();
        return;
    }
    g_document->Show();
    SetLuaDocumentGlobal(g_document);

    while (true)
    {
        if (!m_tasks.empty())
        {
            std::lock_guard _lock(m_mutex);
            for (const auto &task: m_tasks)
                task(g_context);
            m_tasks.clear();
        }

        // Update sandbox timers for running apps (legacy sandbox manager)
        if (m_sandbox_manager) {
            m_sandbox_manager->UpdateTimers();
        }

        // Update RmlUi sandbox timers (for UI-based apps)
        if (g_rmlui_timer_manager) {
            g_rmlui_timer_manager->ProcessTimers();
        }

        m_render_target->bind();
        glClearColor(0.f, 0.f, 0.f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT);
        glViewport(0, 0, 540, 960);

        g_context->Update();
        rmlui_render_interface.SetViewport(540, 960);
        rmlui_render_interface.BeginFrame();
        g_context->Render();
        rmlui_render_interface.EndFrame(m_render_target->framebuffer());

        glFinish();
        {
            std::lock_guard _lock(m_mutex);
            for (const auto& [pid, l] : m_listeners)
                l->onFrameAvailable();
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(16));  // ~60 FPS
    }
    Rml::Shutdown();
}

Kernel::Kernel(const std::shared_ptr<IMosisListener> &listener)
{
    m_listeners.emplace(AIBinder_getCallingPid(), listener);
    m_main_loop_thread = std::thread(&Kernel::main_loop, this);
}

void Kernel::add_listener(const std::shared_ptr<IMosisListener> &listener)
{
    std::lock_guard _lock(m_mutex);
    m_listeners.emplace(AIBinder_getCallingPid(), listener);
    listener->onServiceInitialized(true);
    listener->onBufferAvailable(*m_aidl_buffer);
}

void Kernel::on_touch_down(float x, float y)
{
    Logger::Log(std::format("on_touch_down {} - {}", x, y));
    std::lock_guard _lock(m_mutex);
    m_tasks.emplace_back([x, y](Rml::Context* context){
        int px = static_cast<int>(x * 540);
        int py = static_cast<int>(y * 960);
        bool move_handled = context->ProcessMouseMove(px, py, 0);
        bool down_handled = context->ProcessMouseButtonDown(0, 0);
        Logger::Log(std::format("Touch at ({}, {}): move={}, down={}", px, py, move_handled, down_handled));

        // Debug: Check if there's a hover element
        auto* hover_elem = context->GetHoverElement();
        if (hover_elem) {
            Logger::Log(std::format("  Hover element: {} (id={})",
                hover_elem->GetTagName().c_str(),
                hover_elem->GetId().c_str()));
        } else {
            Logger::Log("  No hover element at this position");
        }
    });
}

void Kernel::on_touch_move(float x, float y)
{
    Logger::Log(std::format("on_touch_move {} - {}", x, y));
    std::lock_guard _lock(m_mutex);
    m_tasks.emplace_back([x, y](Rml::Context* context){
        context->ProcessMouseMove(static_cast<int>(x * 540), static_cast<int>(y * 960), 0);
    });
}

void Kernel::on_touch_up(float x, float y)
{
    Logger::Log(std::format("on_touch_up {} - {}", x, y));
    std::lock_guard _lock(m_mutex);
    m_tasks.emplace_back([x, y](Rml::Context* context){
        context->ProcessMouseMove(static_cast<int>(x * 540), static_cast<int>(y * 960), 0);
        context->ProcessMouseButtonUp(0, 0);
    });
}

Kernel::~Kernel() = default;
