"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const http_1 = require("http");
const trpcExpress = __importStar(require("@trpc/server/adapters/express"));
const database_1 = require("./database");
const router_1 = require("./trpc/router");
const socket_1 = require("./trpc/socket");
const config_1 = require("../../shared/src/config");
const path_1 = __importDefault(require("path"));
const opener_1 = __importDefault(require("opener"));
const terminal_1 = require("../../shared/src/utils/terminal");
const portfinder_1 = __importDefault(require("portfinder"));
const router_2 = __importDefault(require("./otel/router"));
function initializeServer() {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            // Initialize the configuration
            const configManager = config_1.ConfigManager.getInstance();
            const config = configManager.getConfig();
            portfinder_1.default.basePort = 3000;
            portfinder_1.default.highestPort = 5000;
            const availablePort = yield portfinder_1.default.getPortPromise();
            if (availablePort !== config.port) {
                console.log(`Port ${config.port} is already in use.`);
                const useNewPort = yield (0, terminal_1.promptUser)(`Would you like to start the server on port ${availablePort} instead? (y/n): `);
                if (useNewPort) {
                    yield configManager.setPort(availablePort);
                    console.log(`Server will start on port ${availablePort}`);
                }
                else {
                    console.log('Exiting...');
                    process.exit(1);
                }
            }
            // Create APP instance
            const app = (0, express_1.default)();
            const httpServer = (0, http_1.createServer)(app);
            // Initialize the database
            yield (0, database_1.initializeDatabase)(config.database);
            // Set TRPC router
            app.use('/trpc', trpcExpress.createExpressMiddleware({
                router: router_1.appRouter,
            }));
            app.use('/v1', express_1.default.raw({
                type: ['application/x-protobuf', 'application/json'],
                limit: '10mb',
            }), router_2.default);
            // Initialize SocketManager
            socket_1.SocketManager.init(httpServer);
            // Serve static files in development mode
            if (process.env.NODE_ENV === 'production') {
                const publicPath = path_1.default.join(__dirname, '../../public');
                app.use(express_1.default.static(publicPath));
                app.use((req, res, next) => {
                    if (!req.path.startsWith('/trpc')) {
                        res.sendFile(path_1.default.join(publicPath, 'index.html'), {
                            dotfiles: 'allow',
                        });
                    }
                    else {
                        next();
                    }
                });
            }
            httpServer.listen(configManager.getConfig().port, () => {
                const actualPort = configManager.getConfig().port;
                console.log(`Server running on port ${actualPort} in ${process.env.NODE_ENV} mode ...`);
                if (process.env.NODE_ENV === 'production') {
                    (0, opener_1.default)(`http://localhost:${actualPort}/home`);
                }
            });
            return httpServer;
        }
        catch (error) {
            console.error('Error initializing server:', error);
            console.error('Error stack:', error.stack);
            throw error;
        }
    });
}
// Set up the server and start listening
initializeServer()
    .then((server) => {
    // Handle graceful shutdown
    const cleanup = () => {
        console.log('Closing Socket.IO connections');
        socket_1.SocketManager.close();
        console.log('Closing HTTP server');
        server.close(() => {
            console.log('HTTP server closed');
            process.exit(0);
        });
    };
    process.on('SIGTERM', cleanup);
    process.on('SIGINT', cleanup);
})
    .catch(() => {
    process.exit(1);
});
