"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildServer = buildServer;
const path_1 = require("path");
const fs_1 = require("fs");
const promises_1 = require("fs/promises");
const fastify_1 = __importDefault(require("fastify"));
const cors_1 = __importDefault(require("@fastify/cors"));
const static_1 = __importDefault(require("@fastify/static"));
const logger_js_1 = require("./utils/logger.js");
const wiring_js_1 = require("./wiring.js");
const log = (0, logger_js_1.createModuleLogger)('server');
async function buildServer(modules) {
    const app = (0, fastify_1.default)({ logger: true });
    // CORS - allow configured origins or all in production
    const isProduction = process.env.NODE_ENV === 'production';
    await app.register(cors_1.default, {
        origin: isProduction ? true : ['http://localhost:3000', 'http://localhost:5173'],
        methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    });
    // Localhost access restriction (development only)
    if (!isProduction) {
        app.addHook('onRequest', async (request, reply) => {
            const host = request.hostname?.split(':')[0];
            if (host !== 'localhost' && host !== '127.0.0.1') {
                log.warn({ host, ip: request.ip }, 'Blocked non-localhost access');
                reply.code(403).send({ error: 'Access restricted to localhost' });
            }
        });
    }
    // Structured error handler
    app.setErrorHandler((error, request, reply) => {
        log.error({ err: error, url: request.url, method: request.method }, 'Request error');
        const statusCode = error.statusCode ?? 500;
        reply.code(statusCode).send({
            error: statusCode >= 500 ? 'Internal Server Error' : error.message,
            statusCode,
        });
    });
    // Static file serving for data directory
    await app.register(static_1.default, {
        root: (0, path_1.resolve)(process.cwd(), 'data'),
        prefix: '/static/',
        decorateReply: false,
    });
    // Serve frontend SPA build from web/dist (if it exists)
    const webDistDir = (0, path_1.resolve)(process.cwd(), 'web', 'dist');
    if ((0, fs_1.existsSync)(webDistDir)) {
        await app.register(static_1.default, {
            root: webDistDir,
            prefix: '/',
            decorateReply: false,
            wildcard: false,
        });
        // SPA fallback: for any unmatched GET that isn't /api or /static, serve index.html
        app.setNotFoundHandler(async (request, reply) => {
            if (request.method === 'GET' && !request.url.startsWith('/api') && !request.url.startsWith('/static') && !request.url.startsWith('/health')) {
                const indexPath = (0, path_1.resolve)(webDistDir, 'index.html');
                if ((0, fs_1.existsSync)(indexPath)) {
                    const html = await (0, promises_1.readFile)(indexPath, 'utf-8');
                    reply.type('text/html').send(html);
                    return;
                }
            }
            reply.code(404).send({ error: 'Not Found', statusCode: 404 });
        });
    }
    // Health check (available before route plugins)
    app.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
    // Register all route plugins if modules are provided
    if (modules) {
        await (0, wiring_js_1.registerRoutes)(app, modules);
    }
    return app;
}
//# sourceMappingURL=server.js.map