import { Env } from '../../config/env.js';
import Logger from '../../config/logger.js';
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
import { createServer } from '../../node-singletons/http.js';
/**
 * Node.js HTTP Server adapter for standard containers and traditional servers
 * Uses Node.js built-in HTTP server for maximum compatibility
 * Sealed namespace for immutability
 */
export const NodeServerAdapter = Object.freeze({
    /**
     * Create a new Node.js server adapter instance
     */
    create(config) {
        const logger = config.logger ?? createDefaultLogger();
        const state = {};
        return {
            platform: 'nodejs',
            // eslint-disable-next-line @typescript-eslint/require-await
            async handle(_event, _context) {
                throw ErrorFactory.createConfigError('Node.js adapter requires startServer() method. Use RuntimeDetector for automatic initialization.');
            },
            /**
             * Start HTTP server for Node.js environments
             */
            async startServer(port = 3000, host = 'localhost') {
                return startNodeServer(state, config, logger, port, host);
            },
            /**
             * Stop the HTTP server gracefully
             */
            async stop() {
                return stopNodeServer(state, logger);
            },
            parseRequest(_event) {
                throw ErrorFactory.createConfigError('Node.js adapter uses native Node.js HTTP');
            },
            formatResponse(_response) {
                throw ErrorFactory.createConfigError('Node.js adapter uses native Node.js HTTP');
            },
            getLogger() {
                return (logger ?? {
                    debug: (msg) => Logger.debug(`[Node.js] ${msg}`),
                    info: (msg) => Logger.info(`[Node.js] ${msg}`),
                    warn: (msg) => Logger.warn(`[Node.js] ${msg}`),
                    error: (msg, err) => Logger.error(`[Node.js] ${msg}`, err?.message),
                });
            },
            supportsPersistentConnections() {
                return true;
            },
            getEnvironment() {
                return getNodeEnvironment();
            },
        };
    },
});
/**
 * Start Node.js HTTP server
 */
async function startNodeServer(state, config, logger, port, host) {
    return new Promise((resolve, reject) => {
        state.server = createServer((req, res) => {
            handleRequest(req, res, config, logger);
        });
        state.server.listen(port, host, () => {
            logger?.info(`Node.js server listening on http://${host}:${port}`);
            resolve();
        });
        state.server.on('error', (error) => {
            logger?.error('Server error', error);
            reject(error);
        });
        state.server.on('clientError', (error, socket) => {
            if (error.code === 'ECONNRESET' || !socket.writable) {
                return;
            }
            logger?.warn(`Client error: ${error.message}`);
        });
    });
}
/**
 * Stop Node.js HTTP server
 */
async function stopNodeServer(state, logger) {
    return new Promise((resolve) => {
        if (state.server) {
            state.server.close(() => {
                logger?.info('Node.js server stopped');
                resolve();
            });
        }
        else {
            resolve();
        }
    });
}
/**
 * Get Node.js environment
 */
function getNodeEnvironment() {
    return {
        nodeEnv: Env.NODE_ENV,
        runtime: 'nodejs',
        dbConnection: Env.get('DB_CONNECTION', 'sqlite'),
        dbHost: Env.DB_HOST,
        dbPort: Env.DB_PORT,
    };
}
/**
 * Handle request processing
 */
function handleRequest(req, res, config, logger) {
    const chunks = [];
    let body = null;
    // Collect request body
    req.on('data', (chunk) => {
        const maxSize = config.maxBodySize ?? 10 * 1024 * 1024;
        if (chunks.length * chunk.length > maxSize) {
            res.writeHead(413, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Payload Too Large' }));
            req.socket.destroy();
            return;
        }
        chunks.push(chunk);
    });
    req.on('end', async () => {
        try {
            body = chunks.length > 0 ? Buffer.concat(chunks) : null;
            // Set request timeout
            const timeout = config.timeout ?? 30000;
            const timeoutHandle = setTimeout(() => {
                if (!res.headersSent) {
                    res.writeHead(504, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Gateway Timeout' }));
                }
            }, timeout);
            try {
                // Call ZinTrust handler
                await config.handler(req, res, body);
            }
            finally {
                clearTimeout(timeoutHandle);
            }
            logger?.debug('Request processed', {
                method: req.method,
                url: req.url,
                statusCode: res.statusCode,
                remoteAddr: req.socket.remoteAddress,
            });
        }
        catch (error) {
            const err = error;
            logger?.error('Request processing error', err);
            Logger.error('Request processing error', err.message);
            handleError(res, err, logger);
        }
    });
    req.on('error', (error) => {
        Logger.error('Request stream error', error.message);
        handleRequestError(res, error, logger);
    });
}
/**
 * Handle request handler errors
 */
function handleError(res, error, logger) {
    logger?.error('Request handler error', error);
    Logger.error('Request handler error', error.message);
    if (!res.headersSent) {
        res.writeHead(500, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({
            error: 'Internal Server Error',
            statusCode: 500,
            timestamp: new Date().toISOString(),
            ...(Env.get('NODE_ENV') === 'development' && {
                message: error.message,
            }),
        }));
    }
}
/**
 * Handle request stream errors
 */
function handleRequestError(res, error, logger) {
    logger?.error('Request error', error);
    Logger.error('Request error', error.message);
    if (!res.headersSent) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Bad Request' }));
    }
}
function createDefaultLogger() {
    return {
        debug: (msg, data) => Logger.debug(`[Node.js] ${msg}`, data !== undefined && data !== null ? JSON.stringify(data) : ''),
        info: (msg, data) => Logger.info(`[Node.js] ${msg}`, data !== undefined && data !== null ? JSON.stringify(data) : ''),
        warn: (msg, data) => Logger.warn(`[Node.js] ${msg}`, data !== undefined && data !== null ? JSON.stringify(data) : ''),
        error: (msg, err) => Logger.error(`[Node.js] ${msg}`, err?.message),
    };
}
