#pragma once

#include <string>
#include <vector>
#include <cstdint>

// Forward declare lua_State to avoid including lua.h in header
struct lua_State;
struct lua_Debug;

namespace mosis {

// Resource limits for sandbox
struct SandboxLimits {
    size_t memory_bytes = 16 * 1024 * 1024;     // 16 MB default
    size_t max_string_size = 1 * 1024 * 1024;   // 1 MB max string
    size_t max_table_entries = 100000;           // Prevent hash DoS
    uint64_t instructions_per_call = 1000000;    // ~10ms execution
    int stack_depth = 200;                       // Recursion limit
};

// Context for sandbox (app identity, permissions, etc.)
struct SandboxContext {
    std::string app_id;
    std::string app_path;
    std::vector<std::string> permissions;
    bool is_system_app = false;
};

// Isolated Lua execution environment
class LuaSandbox {
public:
    explicit LuaSandbox(const SandboxContext& context,
                        const SandboxLimits& limits = {});
    ~LuaSandbox();

    // Non-copyable, non-movable
    LuaSandbox(const LuaSandbox&) = delete;
    LuaSandbox& operator=(const LuaSandbox&) = delete;
    LuaSandbox(LuaSandbox&&) = delete;
    LuaSandbox& operator=(LuaSandbox&&) = delete;

    // Load and execute Lua code (text only, bytecode rejected)
    bool LoadString(const std::string& code, const std::string& chunk_name = "chunk");
    bool LoadFile(const std::string& path);

    // State access
    lua_State* GetState() const { return m_L; }
    const std::string& GetLastError() const { return m_last_error; }

    // Resource usage
    size_t GetMemoryUsed() const { return m_memory_used; }
    uint64_t GetInstructionsUsed() const { return m_instructions_used; }

    // Context access
    const SandboxContext& GetContext() const { return m_context; }
    const SandboxLimits& GetLimits() const { return m_limits; }
    const std::string& app_id() const { return m_context.app_id; }

    // Reset instruction counter (call before each event handler)
    void ResetInstructionCount();

    // Check if sandbox is in valid state
    bool IsValid() const { return m_L != nullptr; }

private:
    // Setup functions
    void SetupSandbox();
    void RemoveDangerousGlobals();
    void ProtectBuiltinTables();
    void SetupInstructionHook();
    void SetupSafeGlobals();
    void SetupSafeRequire();

    // Allocator callback (static for C compatibility)
    static void* SandboxAlloc(void* ud, void* ptr, size_t osize, size_t nsize);

    // Instruction hook callback (static for C compatibility)
    static void InstructionHook(lua_State* L, lua_Debug* ar);

    // Safe print function
    static int SafePrint(lua_State* L);

    // Safe require function
    static int SafeRequire(lua_State* L);

    lua_State* m_L = nullptr;
    SandboxContext m_context;
    SandboxLimits m_limits;

    size_t m_memory_used = 0;
    uint64_t m_instructions_used = 0;
    std::string m_last_error;
};

} // namespace mosis

// Convenience alias for tests
using SandboxContext = mosis::SandboxContext;
using SandboxLimits = mosis::SandboxLimits;
using LuaSandbox = mosis::LuaSandbox;
