import { appConfig } from '../../config/index.js';
import Logger from '../../config/logger.js';
import { Router } from '../../routes/Router.js';
import { isNonEmptyString, isObject } from '../../helper/index.js';
import * as path from '../../node-singletons/path.js';
import { pathToFileURL } from '../../node-singletons/url.js';
import { detectRuntime } from '../../runtime/detectRuntime.js';
import { ProjectRuntime } from '../../runtime/ProjectRuntime.js';
const isCloudflare = detectRuntime().isCloudflare;
export const isCompiledJsModule = () => {
    // When running from dist, this module is compiled to .js and Node ESM resolution
    // requires explicit file extensions for relative imports.
    const metaUrl = typeof import.meta?.url === 'string' ? import.meta.url : '';
    return metaUrl.endsWith('.js');
};
export const tryImportOptional = async (modulePath) => {
    try {
        return (await import(modulePath));
    }
    catch {
        return undefined;
    }
};
export const tryImportOptionalR = async (modulePath) => {
    try {
        return (await import(modulePath));
    }
    catch (error) {
        Logger.error(`Error importing module ${modulePath}:`, error);
        return undefined;
    }
};
const tryImportRoutesFromAppBase = async (resolvedBasePath) => {
    if (resolvedBasePath === '')
        return undefined;
    const routeCandidates = appConfig.isDevelopment()
        ? [
            path.join(resolvedBasePath, 'routes', 'api.ts'),
            path.join(resolvedBasePath, 'routes', 'api.js'),
        ]
        : [
            path.join(resolvedBasePath, 'routes', 'api.js'),
            path.join(resolvedBasePath, 'dist', 'routes', 'api.js'),
            path.join(resolvedBasePath, 'routes', 'api.ts'),
            path.join(resolvedBasePath, 'dist', 'routes', 'api.ts'),
        ];
    for (const routePath of routeCandidates) {
        try {
            const url = pathToFileURL(routePath).href;
            // eslint-disable-next-line no-await-in-loop
            return (await import(url));
        }
        catch {
            // try next candidate
        }
    }
    return undefined;
};
const registerAppRoutes = async (resolvedBasePath, router) => {
    const mod = await tryImportRoutesFromAppBase(resolvedBasePath);
    if (mod && typeof mod.registerRoutes === 'function') {
        mod.registerRoutes(router);
    }
};
const getProjectRoot = () => {
    const fromEnv = process.env?.['ZINTRUST_PROJECT_ROOT'] ?? '';
    if (fromEnv.trim() !== '')
        return fromEnv.trim();
    return process.cwd();
};
const resolveManifestServiceEnvDir = (projectRoot, entry) => {
    const configRoot = entry.configRoot;
    if (isNonEmptyString(configRoot)) {
        return path.dirname(path.join(projectRoot, configRoot));
    }
    return path.join(projectRoot, 'src', 'services', entry.domain, entry.name);
};
const resolveServicePrefix = (entry) => {
    const prefix = entry.prefix;
    if (isNonEmptyString(prefix)) {
        const segments = prefix
            .split('/')
            .map((segment) => segment.trim())
            .filter((segment) => segment !== '');
        return segments.length === 0 ? '/' : `/${segments.join('/')}`;
    }
    return `/${entry.domain}/${entry.name}`;
};
const ensureManifestServiceEnvLoaded = async (entry) => {
    if (isCloudflare)
        return;
    if (entry.loadEnv === false)
        return;
    const { EnvFileLoader } = await import('../../cli/utils/EnvFileLoader.js');
    const projectRoot = getProjectRoot();
    const envPath = resolveManifestServiceEnvDir(projectRoot, entry);
    EnvFileLoader.ensureLoaded({
        cwd: projectRoot,
        includeCwd: true,
        envPaths: [envPath],
    });
};
const shouldRegisterManifestEntry = (entry, activeService) => {
    if (entry.monolithEnabled === false || typeof entry.loadRoutes !== 'function') {
        return false;
    }
    if (activeService !== undefined && activeService.id !== entry.id) {
        return false;
    }
    return true;
};
const loadRuntimeManifest = async () => {
    if (isCloudflare) {
        await ProjectRuntime.tryLoadWorkerRuntime();
        return;
    }
    await ProjectRuntime.tryLoadNodeRuntime();
};
const registerManifestEntryRoutes = async (router, entry, activeService) => {
    try {
        await ensureManifestServiceEnvLoaded(entry);
        const mod = await entry.loadRoutes?.();
        const registerRoutes = isObject(mod) ? mod.registerRoutes : undefined;
        if (typeof registerRoutes === 'function') {
            registerLoadedRoutes(router, entry, registerRoutes, activeService);
        }
    }
    catch (error) {
        Logger.warn(`Failed to register manifest routes for ${entry.id}`, error);
    }
};
const registerLoadedRoutes = (router, entry, registerRoutes, activeService) => {
    const servicePrefix = resolveServicePrefix(entry);
    if (activeService?.id === entry.id) {
        registerRoutes(router);
        return;
    }
    Router.group(router, servicePrefix, (scopedRouter) => {
        registerRoutes(scopedRouter);
    });
};
const registerManifestRoutes = async (router) => {
    await loadRuntimeManifest();
    const serviceManifest = ProjectRuntime.getServiceManifest();
    if (serviceManifest.length === 0)
        return;
    const activeService = ProjectRuntime.getActiveService();
    if (activeService !== undefined && isCloudflare)
        return;
    for (const entry of serviceManifest) {
        if (!shouldRegisterManifestEntry(entry, activeService))
            continue;
        // eslint-disable-next-line no-await-in-loop
        await registerManifestEntryRoutes(router, entry, activeService);
    }
};
const registerFrameworkRoutes = async (resolvedBasePath, router) => {
    const frameworkRoutes = await tryImportRoutesFromAppBase(resolvedBasePath);
    if (frameworkRoutes && typeof frameworkRoutes.registerRoutes === 'function') {
        frameworkRoutes.registerRoutes(router);
    }
};
const registerGlobalRoutes = (router) => {
    const globalRoutes = globalThis.__zintrustRoutes;
    if (globalRoutes && typeof globalRoutes.registerRoutes === 'function') {
        globalRoutes.registerRoutes(router);
    }
    else {
        Logger.warn('No app routes found and framework routes are unavailable. Ensure routes/api.ts exists in the project.');
    }
};
export const registerMasterRoutes = async (resolvedBasePath, router) => {
    try {
        const activeService = ProjectRuntime.getActiveService();
        if (isCloudflare) {
            registerGlobalRoutes(router);
        }
        if (!isCloudflare && activeService === undefined) {
            await registerAppRoutes(resolvedBasePath, router);
        }
        await registerManifestRoutes(router);
        if (router.routes.length === 0 && activeService === undefined) {
            await registerFrameworkRoutes(resolvedBasePath, router);
        }
        // Always register core framework routes (health, metrics, doc) after app routes
        // This ensures app can override but core routes always exist
        const { registerCoreRoutes } = await import('../../routes/CoreRoutes.js');
        registerCoreRoutes(router);
    }
    catch (error) {
        Logger.error('Failed to register routes:', error);
    }
};
