/*
    ! /server/routers.js
    ? Dynamic Express router loader matching the action loader pattern.
*/

// % imports
import fs from 'fs';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import express from 'express';

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

// % Target directory where the actual route files reside
const routersDir = path.join(__dirname, '..', 'routers');

// $ debug-output
console.info('[Paths] Routers:', routersDir);
export const registeredEndpoints = [];

// $ recursive function to load routers and extract clean endpoints
async function loadRouters(dir = routersDir, baseDir = routersDir, currentPrefix = '') {
    let mainRouter = express.Router();
    const entries = fs.readdirSync(dir, { withFileTypes: true });

    for (const entry of entries) {
        const fullPath = path.join(dir, entry.name);

        if (entry.isDirectory()) {
            // ~ handle subdirectory and extend prefix
            const subPrefix = `${currentPrefix}/${entry.name}`;
            const subRouter = await loadRouters(fullPath, baseDir, subPrefix);
            mainRouter.use(`/${entry.name}`, subRouter);
        } else if (entry.isFile() && entry.name !== 'index.js' && !entry.name.startsWith('.') && entry.name.endsWith('.js')) {
            const fileUrl = pathToFileURL(fullPath).href;
            const module = await import(fileUrl);
            const routeHandler = module.default || module;

            const routeName = entry.name.replace(/\.js$/, '');
            const subRouter = express.Router();

            // ~ pass subrouter into the handler function
            if (typeof routeHandler === 'function') {
                await routeHandler(subRouter);
            }

            const finalFolderPrefix = currentPrefix === '' ? '' : currentPrefix;
            const endpointPath = routeName === 'root' ? finalFolderPrefix || '/' : `${finalFolderPrefix}/${routeName}`;

            // ~ extract methods and paths directly from the sub-router stack
            subRouter.stack.forEach(layer => {
                if (layer.route) {
                    const methods = Object.keys(layer.route.methods).join(', ').toUpperCase();
                    const subRoutePath = layer.route.path === '/' ? '' : layer.route.path;
                    registeredEndpoints.push(`${methods} ${endpointPath}${subRoutePath}`.replace(/\/+/g, '/'));
                }
            });

            if (routeName === 'root') {
                mainRouter.use('/', subRouter);
            } else {
                mainRouter.use(`/${routeName}`, subRouter);
            }
        }
    }
    return mainRouter;
}

// $ Initialize asynchronously and export the loaded routers object
const routers = await loadRouters();

// $ export
export default routers;