/**
 * @module server
 *
 * Native Node.js HTTP & WebSocket server for {{APP_NAME}} — using serve-gib from @ibgib/node-gib.
 */

import { createServer } from 'node:http';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import {
    ServeGib_V1,
    ErrorHandler,
    SyncUpgradeHandler,
    canHandleWsUpgrade,
    handleWsEchoUpgrade,
    getStandardServeGibHandlers,
} from '@ibgib/node-gib/dist/serve-gib/index.mjs';

const __dirname = dirname(fileURLToPath(import.meta.url));

// ---------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------

const PORT = parseInt(process.env.PORT ?? '{{PORT}}', 10);
const DATA_DIR = process.env.DATA_DIR ?? join(__dirname, '{{DATA_DIR_REL}}');
const CLIENT_DIR = join(__dirname, '../client');

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main(): Promise<void> {
    const lc = '[{{APP_NAME}} server]';
    try {
        console.log(`${lc} starting...`);
        console.log(`${lc} dataDir: ${DATA_DIR}`);

        const custodianPrimaryProfile = (process.env.KEYSTONE_PROFILE_CUSTODIAN_PRIMARY || '').trim();
        if (!custodianPrimaryProfile) {
            throw new Error(`${lc} Fatal Error: KEYSTONE_PROFILE_CUSTODIAN_PRIMARY environment variable is missing or blank. (E: {{APP_UUID}})`);
        }

        const isProdEnv = process.env.NODE_ENV === 'production';
        if (isProdEnv && !custodianPrimaryProfile.endsWith('.prod')) {
            throw new Error(`${lc} Security Violation: Non-production keystone profile '${custodianPrimaryProfile}' is prohibited when NODE_ENV=production. (E: {{APP_UUID}})`);
        }

        console.log(`${lc} KEYSTONE_PROFILE_CUSTODIAN_PRIMARY: ${custodianPrimaryProfile} (I: {{APP_UUID}})`);

        if (custodianPrimaryProfile.endsWith('.dev')) {
            console.warn(`\n==========================================================\n⚠️ WARNING: CUSTODIAN KEYSTONE PROFILE IS SET TO DEVELOPMENT ('${custodianPrimaryProfile}')!\nCUSTODIAL KEYSTONES WILL USE LOW-SECURITY DEV PARAMETERS.\nFOR LOCAL TESTING ONLY — DO NOT USE FOR REAL SECRETS OR PRODUCTION DATA!\n==========================================================\n (W: {{APP_UUID}})`);
        } else if (custodianPrimaryProfile.endsWith('.staging')) {
            console.info(`${lc} ℹ️ STAGING CUSTODIAN KEYSTONE PROFILE ACTIVE ('${custodianPrimaryProfile}')`);
        }

        const syncUpgradeHandler = new SyncUpgradeHandler();

        // Initialize serve-gib using standard handler preset from @ibgib/node-gib
        const serveGib = new ServeGib_V1({
            port: PORT,
            dataDir: DATA_DIR,
            handlers: getStandardServeGibHandlers({ clientDir: CLIENT_DIR }),
            errorHandler: new ErrorHandler()
        });

        const server = createServer(async (req, res) => {
            await serveGib.handleRequest(req, res);
        });

        // WebSocket upgrade handling for symmetric sync
        server.on('upgrade', async (req, socket, head) => {
            const reqCtx = await serveGib.prepareContext(req);

            const isSync = await syncUpgradeHandler.handleUpgrade(reqCtx, socket as any, head);

            if (!isSync && canHandleWsUpgrade(req)) {
                handleWsEchoUpgrade(req, socket as any, head);
            } else if (!isSync) {
                socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
                socket.destroy();
            }
        });

        server.listen(PORT, '0.0.0.0', () => {
            console.log(`${lc} listening on http://0.0.0.0:${PORT}`);
        });

    } catch (error) {
        console.error(`${lc} fatal: ${extractErrorMsg(error)}`);
        process.exit(1);
    }
}

main();
