// D:\Dev\Mosis\MosisService\src\main\kernel\src\kernel.cpp
// Platform-agnostic kernel implementation

#include "service_interface.h"
#include "platform.h"
#include "file_interface.h"
#include "RmlUi_Renderer_GL3.h"
#include <RmlUi/Core.h>
#include <RmlUi/Lua.h>
#include <RmlUi/Lua/Interpreter.h>
#include <mutex>
#include <vector>
#include <functional>
#include <atomic>
#include <thread>
#include <chrono>

namespace mosis {

// Global state for Lua access
static Rml::Context* g_context = nullptr;
static Rml::ElementDocument* g_document = nullptr;

// System interface using platform abstraction
class PlatformSystemInterface : public Rml::SystemInterface {
public:
    double GetElapsedTime() override {
        static auto start_time = std::chrono::steady_clock::now();
        auto now = std::chrono::steady_clock::now();
        return std::chrono::duration<double>(now - start_time).count();
    }

    bool LogMessage(Rml::Log::Type type, const Rml::String& message) override {
        const char* type_str = "";
        switch (type) {
            case Rml::Log::LT_ERROR:   type_str = "[ERROR]"; break;
            case Rml::Log::LT_WARNING: type_str = "[WARN]"; break;
            case Rml::Log::LT_INFO:    type_str = "[INFO]"; break;
            default: type_str = "[DEBUG]"; break;
        }
        GetPlatform().Log(std::string(type_str) + " " + message);
        return true;
    }
};

static PlatformSystemInterface g_system_interface;

// 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);
    GetPlatform().Log(std::string("Loading screen: ") + 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();
        GetPlatform().Log(std::string("Loaded screen: ") + path);
        lua_pushboolean(L, true);
    } else {
        GetPlatform().Log(std::string("Failed to load screen: ") + path);
        lua_pushboolean(L, false);
    }

    return 1;
}

// Register Lua functions for navigation
static void RegisterLuaFunctions() {
    lua_State* L = Rml::Lua::Interpreter::GetLuaState();
    lua_pushcfunction(L, LuaLoadScreen);
    lua_setglobal(L, "loadScreen");
    GetPlatform().Log("Registered Lua loadScreen function");
}

// Kernel implementation
class KernelImpl : public IKernel {
public:
    KernelImpl() = default;
    ~KernelImpl() override {
        Stop();
    }

    void AddListener(std::shared_ptr<IServiceListener> listener) override {
        std::lock_guard lock(m_mutex);
        m_listeners.push_back(listener);
        if (m_initialized) {
            listener->OnServiceInitialized(true);
            listener->OnBufferAvailable();
        }
    }

    void RemoveListener(std::shared_ptr<IServiceListener> listener) override {
        std::lock_guard lock(m_mutex);
        m_listeners.erase(
            std::remove(m_listeners.begin(), m_listeners.end(), listener),
            m_listeners.end()
        );
    }

    void OnTouchDown(float x, float y) override {
        std::lock_guard lock(m_mutex);
        auto& platform = GetPlatform();
        int px = static_cast<int>(x * platform.GetWidth());
        int py = static_cast<int>(y * platform.GetHeight());
        m_tasks.emplace_back([px, py](Rml::Context* ctx) {
            ctx->ProcessMouseMove(px, py, 0);
            ctx->ProcessMouseButtonDown(0, 0);
        });
    }

    void OnTouchMove(float x, float y) override {
        std::lock_guard lock(m_mutex);
        auto& platform = GetPlatform();
        int px = static_cast<int>(x * platform.GetWidth());
        int py = static_cast<int>(y * platform.GetHeight());
        m_tasks.emplace_back([px, py](Rml::Context* ctx) {
            ctx->ProcessMouseMove(px, py, 0);
        });
    }

    void OnTouchUp(float x, float y) override {
        std::lock_guard lock(m_mutex);
        auto& platform = GetPlatform();
        int px = static_cast<int>(x * platform.GetWidth());
        int py = static_cast<int>(y * platform.GetHeight());
        m_tasks.emplace_back([px, py](Rml::Context* ctx) {
            ctx->ProcessMouseMove(px, py, 0);
            ctx->ProcessMouseButtonUp(0, 0);
        });
    }

    void OnBackButton() override {
        std::lock_guard lock(m_mutex);
        m_tasks.emplace_back([](Rml::Context* ctx) {
            // Execute goBack() Lua function if available
            lua_State* L = Rml::Lua::Interpreter::GetLuaState();
            lua_getglobal(L, "goBack");
            if (lua_isfunction(L, -1)) {
                lua_call(L, 0, 0);
            } else {
                lua_pop(L, 1);
            }
        });
    }

    void OnHomeButton() override {
        std::lock_guard lock(m_mutex);
        m_tasks.emplace_back([](Rml::Context* ctx) {
            // Execute goHome() Lua function if available
            lua_State* L = Rml::Lua::Interpreter::GetLuaState();
            lua_getglobal(L, "goHome");
            if (lua_isfunction(L, -1)) {
                lua_call(L, 0, 0);
            } else {
                lua_pop(L, 1);
            }
        });
    }

    void OnRecentsButton() override {
        // TODO: Implement recents/app switcher
        GetPlatform().Log("Recents button pressed (not implemented)");
    }

    void RequestReload() override {
        m_reload_requested = true;
    }

    void NavigateTo(const std::string& screen) override {
        std::lock_guard lock(m_mutex);
        std::string path = screen;
        m_tasks.emplace_back([path](Rml::Context* ctx) {
            lua_State* L = Rml::Lua::Interpreter::GetLuaState();
            lua_getglobal(L, "navigateTo");
            if (lua_isfunction(L, -1)) {
                lua_pushstring(L, path.c_str());
                lua_call(L, 1, 0);
            } else {
                lua_pop(L, 1);
            }
        });
    }

    void Start() override {
        if (m_running) return;
        m_running = true;
        m_main_thread = std::thread(&KernelImpl::MainLoop, this);
    }

    void Stop() override {
        m_running = false;
        if (m_main_thread.joinable()) {
            m_main_thread.join();
        }
    }

    bool IsRunning() const override {
        return m_running;
    }

private:
    void MainLoop() {
        auto& platform = GetPlatform();
        uint32_t width = platform.GetWidth();
        uint32_t height = platform.GetHeight();

        // Initialize RmlUi render interface
        RenderInterface_GL3 render_interface;
        if (!render_interface) {
            platform.Log("Failed to create render interface");
            return;
        }

        // Set up RmlUi
        Rml::SetRenderInterface(&render_interface);
        Rml::SetFileInterface(&platform.GetFileInterface());
        Rml::SetSystemInterface(&g_system_interface);
        Rml::Initialise();
        Rml::Lua::Initialise();
        platform.Log("RmlUi initialized with Lua bindings");

        // Register navigation functions
        RegisterLuaFunctions();

        // Create context with platform resolution
        g_context = Rml::CreateContext("default", Rml::Vector2i(width, height));
        if (!g_context) {
            platform.Log("Failed to create RmlUi context");
            Rml::Shutdown();
            return;
        }

        // Load fonts
        LoadFonts();

        // Load initial document
        g_document = g_context->LoadDocument("apps/home/home.rml");
        if (!g_document) {
            platform.Log("Failed to load home.rml document");
            Rml::Shutdown();
            return;
        }
        g_document->Show();

        // Notify listeners
        {
            std::lock_guard lock(m_mutex);
            m_initialized = true;
            for (auto& listener : m_listeners) {
                listener->OnServiceInitialized(true);
                listener->OnBufferAvailable();
            }
        }

        // Main loop
        while (m_running) {
            // Handle reload request
            if (m_reload_requested.exchange(false)) {
                ReloadCurrentDocument();
            }

            // Process pending tasks
            {
                std::lock_guard lock(m_mutex);
                for (const auto& task : m_tasks) {
                    task(g_context);
                }
                m_tasks.clear();
            }

            // Render
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            glViewport(0, 0, width, height);

            g_context->Update();
            render_interface.SetViewport(width, height);
            render_interface.BeginFrame();
            g_context->Render();
            render_interface.EndFrame(0);  // 0 = default framebuffer on desktop

            glFinish();

            // Notify listeners
            {
                std::lock_guard lock(m_mutex);
                for (auto& listener : m_listeners) {
                    listener->OnFrameAvailable();
                }
            }

            std::this_thread::sleep_for(std::chrono::milliseconds(16));  // ~60 FPS
        }

        // Cleanup
        g_document = nullptr;
        g_context = nullptr;
        Rml::Shutdown();
    }

    void LoadFonts() {
        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");
    }

    void ReloadCurrentDocument() {
        if (!g_context || !g_document) return;

        GetPlatform().Log("Reloading current document...");

        // Get current document path
        std::string current_path = g_document->GetSourceURL();

        // Unload and reload
        g_context->UnloadDocument(g_document);
        g_document = g_context->LoadDocument(current_path);
        if (g_document) {
            g_document->Show();
            GetPlatform().Log("Document reloaded: " + current_path);
        } else {
            GetPlatform().Log("Failed to reload document: " + current_path);
        }
    }

    std::mutex m_mutex;
    std::vector<std::shared_ptr<IServiceListener>> m_listeners;
    std::vector<std::function<void(Rml::Context*)>> m_tasks;
    std::thread m_main_thread;
    std::atomic<bool> m_running{false};
    std::atomic<bool> m_reload_requested{false};
    bool m_initialized{false};
};

// Platform singleton
static std::unique_ptr<IPlatform> g_platform;

IPlatform& GetPlatform() {
    return *g_platform;
}

void SetPlatform(std::unique_ptr<IPlatform> platform) {
    g_platform = std::move(platform);
}

// Factory function
std::unique_ptr<IKernel> CreateKernel() {
    return std::make_unique<KernelImpl>();
}

} // namespace mosis
