// sandbox_manager.cpp - Multi-app sandbox orchestrator implementation
// Milestone 20: Kernel Integration

#include "sandbox_manager.h"
#include <lua.hpp>
#include <filesystem>

namespace mosis {

LuaSandboxManager::LuaSandboxManager(const std::string& data_root)
    : m_data_root(data_root)
    , m_audit_log()
    , m_rate_limiter()
    , m_message_bus()
    , m_timer_manager()
{
    // Set reasonable default limits
    m_default_limits.memory_bytes = 50 * 1024 * 1024;      // 50MB per app
    m_default_limits.instructions_per_call = 1000000;      // 1M instructions
    m_default_limits.stack_depth = 200;                    // 200 recursion depth
    m_default_limits.max_string_size = 10 * 1024 * 1024;   // 10MB strings
}

LuaSandboxManager::~LuaSandboxManager() {
    // Stop all running apps
    std::lock_guard<std::mutex> lock(m_mutex);
    for (auto& [app_id, app] : m_apps) {
        if (app && app->is_running) {
            CleanupApp(*app);
        }
    }
    m_apps.clear();
}

bool LuaSandboxManager::StartApp(const std::string& app_id,
                                  const std::string& app_path,
                                  const std::vector<std::string>& permissions,
                                  bool is_system_app) {
    std::lock_guard<std::mutex> lock(m_mutex);

    // Check if already running
    if (m_apps.count(app_id) && m_apps[app_id]->is_running) {
        return false;  // Already running
    }

    // Create sandbox context
    SandboxContext ctx;
    ctx.app_id = app_id;
    ctx.app_path = app_path;
    ctx.permissions = permissions;
    ctx.is_system_app = is_system_app;

    // Create app sandbox
    auto app = CreateAppSandbox(ctx);
    if (!app) {
        m_audit_log.Log(AuditEvent::AppStart, app_id,
                        "FAILED", "Failed to create sandbox");
        return false;
    }

    // Register all APIs
    RegisterAPIs(*app);

    // Mark as running
    app->is_running = true;

    // Store in map
    m_apps[app_id] = std::move(app);

    // Log successful start
    m_audit_log.Log(AuditEvent::AppStart, app_id, "SUCCESS", "");

    return true;
}

bool LuaSandboxManager::StopApp(const std::string& app_id) {
    std::lock_guard<std::mutex> lock(m_mutex);

    auto it = m_apps.find(app_id);
    if (it == m_apps.end() || !it->second->is_running) {
        return false;  // Not running
    }

    // Clean up resources
    CleanupApp(*it->second);

    // Mark as stopped
    it->second->is_running = false;

    // Log stop
    m_audit_log.Log(AuditEvent::AppStop, app_id, "SUCCESS", "");

    // Remove from map
    m_apps.erase(it);

    return true;
}

bool LuaSandboxManager::IsAppRunning(const std::string& app_id) const {
    std::lock_guard<std::mutex> lock(m_mutex);
    auto it = m_apps.find(app_id);
    return it != m_apps.end() && it->second->is_running;
}

AppSandbox* LuaSandboxManager::GetApp(const std::string& app_id) {
    std::lock_guard<std::mutex> lock(m_mutex);
    auto it = m_apps.find(app_id);
    if (it != m_apps.end() && it->second->is_running) {
        return it->second.get();
    }
    return nullptr;
}

const AppSandbox* LuaSandboxManager::GetApp(const std::string& app_id) const {
    std::lock_guard<std::mutex> lock(m_mutex);
    auto it = m_apps.find(app_id);
    if (it != m_apps.end() && it->second->is_running) {
        return it->second.get();
    }
    return nullptr;
}

bool LuaSandboxManager::ExecuteCode(const std::string& app_id,
                                     const std::string& code,
                                     const std::string& source_name) {
    std::lock_guard<std::mutex> lock(m_mutex);

    auto it = m_apps.find(app_id);
    if (it == m_apps.end() || !it->second->is_running) {
        return false;
    }

    return it->second->lua->LoadString(code, source_name);
}

bool LuaSandboxManager::LoadFile(const std::string& app_id,
                                  const std::string& path) {
    std::lock_guard<std::mutex> lock(m_mutex);

    auto it = m_apps.find(app_id);
    if (it == m_apps.end() || !it->second->is_running) {
        return false;
    }

    return it->second->lua->LoadFile(path);
}

void LuaSandboxManager::RecordUserGesture(const std::string& app_id) {
    std::lock_guard<std::mutex> lock(m_mutex);

    auto it = m_apps.find(app_id);
    if (it != m_apps.end() && it->second->is_running) {
        it->second->permissions->RecordUserGesture();
    }
}

void LuaSandboxManager::UpdateTimers() {
    // Fire all ready timers
    m_timer_manager.ProcessTimers();
}

std::vector<std::string> LuaSandboxManager::GetRunningApps() const {
    std::lock_guard<std::mutex> lock(m_mutex);
    std::vector<std::string> result;
    for (const auto& [app_id, app] : m_apps) {
        if (app && app->is_running) {
            result.push_back(app_id);
        }
    }
    return result;
}

size_t LuaSandboxManager::GetRunningAppCount() const {
    std::lock_guard<std::mutex> lock(m_mutex);
    size_t count = 0;
    for (const auto& [app_id, app] : m_apps) {
        if (app && app->is_running) {
            count++;
        }
    }
    return count;
}

std::unique_ptr<AppSandbox> LuaSandboxManager::CreateAppSandbox(
    const SandboxContext& ctx) {
    auto app = std::make_unique<AppSandbox>();
    app->context = ctx;

    // Create core sandbox
    app->lua = std::make_unique<LuaSandbox>(ctx, m_default_limits);

    // Create permission gate
    app->permissions = std::make_unique<PermissionGate>(ctx);
    for (const auto& perm : ctx.permissions) {
        if (!ctx.is_system_app) {
            // Normal apps need explicit grants for dangerous permissions
            auto cat = app->permissions->GetCategory(perm);
            if (cat == PermissionCategory::Normal) {
                app->permissions->GrantPermission(perm);
            }
        } else {
            // System apps get all declared permissions
            app->permissions->GrantPermission(perm);
        }
    }

    // Create storage path
    std::string app_data_path = m_data_root + "/apps/" + ctx.app_id;
    std::filesystem::create_directories(app_data_path + "/data");
    std::filesystem::create_directories(app_data_path + "/cache");
    std::filesystem::create_directories(app_data_path + "/db");

    // Create virtual filesystem
    app->filesystem = std::make_unique<VirtualFS>(ctx.app_id, app_data_path);

    // Create database manager
    app->database = std::make_unique<DatabaseManager>(ctx.app_id, app_data_path + "/db");

    // Create network components
    app->network = std::make_unique<NetworkManager>(ctx.app_id);
    app->websocket = std::make_unique<WebSocketManager>(ctx.app_id);

    // Create hardware interfaces
    app->camera = std::make_unique<CameraInterface>(ctx.app_id, app->permissions.get());
    app->microphone = std::make_unique<MicrophoneInterface>(ctx.app_id, app->permissions.get());
    app->audio = std::make_unique<AudioOutputInterface>(ctx.app_id);
    app->location = std::make_unique<LocationInterface>(ctx.app_id);
    app->sensors = std::make_unique<SensorInterface>(ctx.app_id);
    app->bluetooth = std::make_unique<BluetoothInterface>(ctx.app_id);
    app->contacts = std::make_unique<ContactsInterface>(ctx.app_id);

    return app;
}

void LuaSandboxManager::RegisterAPIs(AppSandbox& app) {
    lua_State* L = app.lua->GetState();
    if (!L) return;

    // Register JSON API
    RegisterJsonAPI(L);

    // Register crypto API
    RegisterCryptoAPI(L);

    // Register timer APIs with the shared timer manager
    // Note: Individual API registration would be done here if we
    // were exposing these to Lua. For now, the timer manager
    // provides the backend and apps use it via registered functions.

    // Store app context in registry for API callbacks
    lua_pushlightuserdata(L, &app);
    lua_setfield(L, LUA_REGISTRYINDEX, "__app_sandbox");

    // Store manager reference for cross-app operations
    lua_pushlightuserdata(L, this);
    lua_setfield(L, LUA_REGISTRYINDEX, "__sandbox_manager");
}

void LuaSandboxManager::CleanupApp(AppSandbox& app) {
    // Clear timers for this app
    m_timer_manager.ClearAppTimers(app.context.app_id);

    // Close WebSocket connections
    if (app.websocket) {
        app.websocket->CloseAll();
    }

    // Stop camera/microphone sessions
    if (app.camera) {
        app.camera->Shutdown();
    }
    if (app.microphone) {
        app.microphone->Shutdown();
    }

    // Stop audio
    if (app.audio) {
        app.audio->Shutdown();
    }

    // Stop location watching
    if (app.location) {
        app.location->Shutdown();
    }

    // Stop sensors
    if (app.sensors) {
        app.sensors->Shutdown();
    }

    // Stop bluetooth
    if (app.bluetooth) {
        app.bluetooth->Shutdown();
    }

    // Clean up temp files in filesystem
    if (app.filesystem) {
        app.filesystem->ClearTemp();
    }

    // Close database connections
    if (app.database) {
        app.database->CloseAll();
    }

    // Unregister from message bus
    m_message_bus.UnregisterApp(app.context.app_id);
}

} // namespace mosis
