import { readFileSync, readdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { getProjectDir } from '../storage/mini-app-store.js';
import * as miniAppStore from '../storage/mini-app-store.js';
import { broadcastToWorkspace } from '../ws/connection-manager.js';
import { listTasks } from './mini-app-tasks.js';
const registries = new Map();
function servicesDir(projectId) {
    return join(getProjectDir(projectId), 'src', 'services');
}
/**
 * 编译单个 service 文件：剥离 import 行（services 不依赖外部模块），
 * 把 ESM `export default` 转为 CJS `module.exports =`，在沙箱里求值。
 * 默认导出应为 { eventName: handler }。
 */
function compileService(code) {
    const stripped = code
        .replace(/^\s*import\s+.*$/gm, '')
        .replace(/\bexport\s+default\s+/, 'module.exports = ');
    const moduleObj = { exports: {} };
    const fn = new Function('module', 'exports', stripped);
    fn(moduleObj, moduleObj.exports);
    const exported = moduleObj.exports;
    if (!exported || typeof exported !== 'object')
        return {};
    const handlers = {};
    for (const [name, h] of Object.entries(exported)) {
        if (typeof h === 'function')
            handlers[name] = h;
    }
    return handlers;
}
function loadRegistry(projectId) {
    const cached = registries.get(projectId);
    if (cached)
        return cached;
    const registry = new Map();
    const dir = servicesDir(projectId);
    if (existsSync(dir)) {
        for (const entry of readdirSync(dir, { withFileTypes: true })) {
            if (entry.isDirectory() || !/\.(js|mjs|cjs)$/.test(entry.name))
                continue;
            try {
                const code = readFileSync(join(dir, entry.name), 'utf-8');
                const handlers = compileService(code);
                for (const [name, h] of Object.entries(handlers))
                    registry.set(name, h);
            }
            catch (err) {
                console.error(`[mini-app-services] failed to load ${entry.name}:`, err instanceof Error ? err.message : err);
            }
        }
    }
    registries.set(projectId, registry);
    return registry;
}
function makeContext(projectId) {
    return {
        projectId,
        readConfig: (path) => miniAppStore.readConfig(projectId, path),
        writeConfig: (path, value) => {
            miniAppStore.writeConfig(projectId, path, value);
            broadcastToWorkspace(projectId, 'miniApp.configChanged', { path, value });
        },
        updateConfig: (path, updater) => {
            const prev = miniAppStore.readConfig(projectId, path);
            const next = updater(prev);
            miniAppStore.writeConfig(projectId, path, next);
            broadcastToWorkspace(projectId, 'miniApp.configChanged', { path, value: next });
            return next;
        },
        listRunningTasks: () => listTasks(projectId).filter((t) => t.status === 'running'),
        broadcast: (event, data) => broadcastToWorkspace(projectId, event, data),
    };
}
/** 调用某项目的 service handler。handler 不存在则抛错。 */
export async function invokeService(projectId, name, payload) {
    const registry = loadRegistry(projectId);
    const handler = registry.get(name);
    if (!handler)
        throw new Error(`Service handler not found: ${name}`);
    const ctx = makeContext(projectId);
    return await handler(payload, ctx);
}
/** 项目删除/卸载时清理缓存。 */
export function unloadServices(projectId) {
    registries.delete(projectId);
}
/** services 文件变更后重载（预留：file watcher 或手动刷新调用）。 */
export function reloadServices(projectId) {
    registries.delete(projectId);
    loadRegistry(projectId);
}
/**
 * 服务器启动检查：遍历所有 mini-app 项目，若某项目尚未落地 agents.json，
 * 但其 manifest 声明了 `agents` 种子数组，则把种子写入 agents.json。
 *
 * - 已存在 agents.json 的项目一律跳过 —— 绝不覆盖用户既有配置（哪怕文件损坏）。
 * - 无种子（manifest 未声明 agents 或为空数组）的项目跳过。
 * - 首次落地只写 agents.json，不改 manifest.updatedAt（后台初始化，无副作用）。
 *
 * 这样预览页 agent 对话（读 agents.json）在项目首次启用时即可用，
 * 用户无需手动创建 agents.json。
 */
export function ensureAgentsConfigs() {
    const projects = miniAppStore.listProjects();
    for (const project of projects) {
        if (miniAppStore.agentsConfigExists(project.id))
            continue;
        const agents = project.agents;
        if (!Array.isArray(agents) || agents.length === 0)
            continue;
        miniAppStore.writeAgentsConfig(project.id, agents);
        console.log(`[mini-app-services] initialized agents.json for ${project.id} (${agents.length} agent(s)) from manifest seed`);
    }
}
//# sourceMappingURL=mini-app-services.js.map