import Fastify from "fastify";
import cors from "@fastify/cors";
import fastifyStatic from "@fastify/static";
import { existsSync } from "node:fs";
import { join, dirname } from "node:path";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const { version: PKG_VERSION } = require("../package.json");
const __dirname = dirname(fileURLToPath(import.meta.url));
import { registerChatRoutes } from "./routes/chat.js";
import { registerHealthRoutes } from "./routes/health.js";
import { registerSessionRoutes } from "./routes/sessions.js";
import { registerAuthRoutes } from "./routes/auth.js";
import { registerTerminalRoutes } from "./routes/terminals.js";
import { registerConsentRoutes } from "./routes/consent.js";
import { registerTrustRoutes } from "./routes/trust.js";
import { registerHookRoutes } from "./routes/hooks.js";
import { registerJobRoutes } from "./routes/jobs.js";
import { registerMobileRoutes } from "./routes/mobile.js";
import { registerNetworkRoutes } from "./routes/network.js";
import { registerVoiceRoutes } from "./routes/voice.js";
import { registerWorkspaceRoutes } from "./routes/workspace.js";
import { registerScreenShareRoutes } from "./routes/screen-share.js";
import { registerFilesystemRoutes } from "./routes/filesystem.js";
import { registerThreadRoutes } from "./routes/threads.js";
import { registerRepoRoutes } from "./routes/repositories.js";
import { registerPlanRoutes } from "./routes/plans.js";
import { registerMaintenanceRoutes } from "./routes/maintenance.js";
import { registerMcpRoutes } from "./routes/mcp-server.js";
import { registerGitRoutes } from "./routes/git.js";
import { registerUpdateRoutes } from "./routes/update.js";
import { getSchemaVersion } from "./db/connection.js";
export async function createServer(config, deps = {}) {
    const app = Fastify({
        logger: {
            level: config.logLevel,
        },
    });
    await app.register(cors, {
        origin: true, // allow any origin — auth is JWT-based, not origin-based
        methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    });
    registerHealthRoutes(app, config, {
        getDeviceCount: () => deps.deviceRegistry?.count() ?? 0,
        getSchemaVersion: () => deps.sqlite ? getSchemaVersion(deps.sqlite) : 0,
    });
    if (deps.userService) {
        registerAuthRoutes(app, config, deps.userService, deps.toolRegistry);
    }
    registerChatRoutes(app, config, {
        db: deps.db,
        sessionService: deps.sessionService,
        toolRegistry: deps.toolRegistry,
        surfaceRegistry: deps.surfaceRegistry,
        audit: deps.audit,
        toolExecutor: deps.toolExecutor,
        memoryService: deps.memoryService,
        userService: deps.userService,
        ws: deps.ws,
        sessionState: deps.sessionState,
        providerRegistry: deps.providerRegistry,
    });
    if (deps.sessionService && deps.audit) {
        registerSessionRoutes(app, config, deps.sessionService, deps.audit, deps.hooks, deps.sessionState);
    }
    if (deps.surfaceRegistry && deps.toolRegistry && deps.audit) {
        registerTerminalRoutes(app, deps.surfaceRegistry, deps.toolRegistry, deps.audit, deps.toolExecutor);
    }
    if (deps.consentManager && deps.audit) {
        registerConsentRoutes(app, deps.consentManager, deps.audit);
    }
    if (deps.voiceService && deps.consentManager) {
        registerVoiceRoutes(app, deps.voiceService, deps.consentManager, config, deps.userService);
    }
    if (deps.trustEngine) {
        registerTrustRoutes(app, deps.trustEngine);
    }
    if (deps.hooks && deps.hookSecret && deps.onWakeHook && deps.onAgentHook) {
        registerHookRoutes(app, {
            hooks: deps.hooks,
            hookSecret: deps.hookSecret,
            onWake: deps.onWakeHook,
            onAgentHook: deps.onAgentHook,
        });
    }
    if (deps.scheduler) {
        registerJobRoutes(app, config, deps.scheduler);
    }
    if (deps.deviceRegistry && deps.consentManager) {
        registerMobileRoutes(app, {
            deviceRegistry: deps.deviceRegistry,
            consentManager: deps.consentManager,
            sessionService: deps.sessionService,
        });
    }
    registerNetworkRoutes(app, deps.ws, deps.sqlite, deps.providerRegistry);
    if (deps.screenShare && deps.ws) {
        registerScreenShareRoutes(app, { screenShare: deps.screenShare, ws: deps.ws });
    }
    registerFilesystemRoutes(app, deps.ws);
    if (deps.surfaceRegistry) {
        registerWorkspaceRoutes(app, deps.surfaceRegistry, deps.sessionState, deps.sessionService, deps.ws);
    }
    // Git API routes
    registerGitRoutes(app, config, {
        ws: deps.ws,
        userService: deps.userService,
        providerRegistry: deps.providerRegistry,
    });
    // Agent threads + provider routes
    if (deps.threadService && deps.providerRegistry) {
        registerThreadRoutes(app, config, {
            threadService: deps.threadService,
            providerRegistry: deps.providerRegistry,
            userService: deps.userService,
            repoService: deps.repoService,
            ws: deps.ws,
            gitService: deps.gitService,
        });
    }
    // Automation repository routes
    if (deps.repoService) {
        registerRepoRoutes(app, config, {
            repoService: deps.repoService,
            userService: deps.userService,
            ws: deps.ws,
        });
    }
    // Automation plan routes
    if (deps.planService && deps.repoService) {
        registerPlanRoutes(app, config, {
            planService: deps.planService,
            repoService: deps.repoService,
            threadService: deps.threadService,
            providerRegistry: deps.providerRegistry,
            userService: deps.userService,
            ws: deps.ws,
        });
    }
    // Maintenance routes (supervised self-test/self-fix)
    if (deps.maintenanceService) {
        registerMaintenanceRoutes(app, config, {
            maintenanceService: deps.maintenanceService,
            notifications: deps.notifications,
            ws: deps.ws,
        });
    }
    // MCP SSE server for external CLI agents
    if (deps.toolRegistry) {
        registerMcpRoutes(app, { toolRegistry: deps.toolRegistry, config });
    }
    // Self-update routes
    if (deps.shutdown) {
        registerUpdateRoutes(app, config, { shutdown: deps.shutdown, port: config.port });
    }
    // ── Serve the web frontend (SPA) if the built files exist ────────
    // Probe paths in order: JAIT_WEB_DIR env, co-located ../web/dist
    // (npm global install), monorepo apps/web/dist (dev)
    const webDir = resolveWebDir();
    if (webDir) {
        await app.register(fastifyStatic, {
            root: webDir,
            prefix: "/",
            decorateReply: false,
            // Don't serve index.html for API routes
        });
        // SPA fallback — serve index.html for any non-API, non-file GET
        app.setNotFoundHandler(async (request, reply) => {
            if (request.method === "GET" && !request.url.startsWith("/api") && !request.url.startsWith("/health")) {
                const indexPath = join(webDir, "index.html");
                const html = await readFile(indexPath, "utf8");
                return reply.type("text/html").send(html);
            }
            return reply.status(404).send({ error: "Not Found" });
        });
        console.log(`Serving web UI from ${webDir}`);
    }
    else {
        app.get("/", async () => ({
            name: "jait-gateway",
            version: PKG_VERSION,
            status: "ok",
        }));
    }
    return app;
}
/** Resolve the directory containing the built web frontend. */
function resolveWebDir() {
    // Explicit env override
    if (process.env["JAIT_WEB_DIR"] && existsSync(process.env["JAIT_WEB_DIR"])) {
        return process.env["JAIT_WEB_DIR"];
    }
    const candidates = [
        // Bundled inside gateway package (npm publish + global install)
        join(__dirname, "../web-dist"),
        // Monorepo dev layout (bun run dev)
        join(__dirname, "../../../../apps/web/dist"),
    ];
    for (const dir of candidates) {
        if (existsSync(join(dir, "index.html")))
            return dir;
    }
    return null;
}
//# sourceMappingURL=server.js.map