import path from 'node:path';
import assert from 'node:assert';
import { config } from 'dotenv';
import { readPackageUp } from 'read-package-up';
import { isDev } from './env.js';
import { startWithTelemetry } from './telemetry/index.js';
function resolveMain(packageJson) {
    if (typeof packageJson.main === 'string') {
        return packageJson.main;
    }
    return undefined;
}
async function getServiceDetails(argv = {}) {
    if (argv.name && argv.root) {
        return {
            rootDirectory: argv.root,
            name: argv.name,
            version: argv.version || '0.0.0',
            main: argv.main || (isDev() && !argv.built ? 'src/index.ts' : 'build/index.js'),
        };
    }
    const cwd = argv.packageDir ? path.resolve(argv.packageDir) : process.cwd();
    const pkg = await readPackageUp({ cwd });
    if (!pkg) {
        throw new Error(`Unable to find package.json in ${cwd} to get main module. Make sure you are running from the package root directory.`);
    }
    const main = resolveMain(pkg.packageJson);
    const parts = pkg.packageJson.name.split('/');
    return {
        main,
        rootDirectory: path.dirname(pkg.path),
        name: parts[parts.length - 1],
        version: pkg.packageJson.version,
        customizer: pkg.packageJson.config?.telemetry?.customizer,
    };
}
function getBuildDir(main) {
    const dir = /^(?:\.?\/?)(build|dist)\//.exec(main);
    assert(dir, 'Could not determine build directory - should be dist or build');
    return dir[1];
}
// Automagically start your app by using common patterns
// to find your implementation and settings. This is most useful
// for jobs or other scripts that need service infra but are
// not simply the service
export async function bootstrap(argv) {
    const { main, rootDirectory, name, version, customizer } = await getServiceDetails(argv);
    let entrypoint;
    let codepath = 'build';
    if (isDev() && argv?.built !== true) {
        await import('tsx/esm');
        if (main) {
            entrypoint = main.replace(/^(\.?\/?)(build|dist)\//, '$1src/').replace(/\.js$/, '.ts');
        }
        else {
            entrypoint = './src/index.ts';
        }
        codepath = 'src';
    }
    else if (main) {
        codepath = getBuildDir(main);
        entrypoint = main;
    }
    else {
        entrypoint = './build/index.js';
    }
    config({ quiet: true });
    const absoluteEntrypoint = path.resolve(rootDirectory, entrypoint);
    if (argv?.telemetry) {
        let otelCustomizer = undefined;
        if (customizer) {
            // Customize OTEL with a dynamic import based on the codePath (so put it in src, generally)
            otelCustomizer = (await import(path.resolve(`${codepath}/${customizer}`)))
                .NodeSDKConfiguration;
            if (typeof otelCustomizer === 'object') {
                otelCustomizer = (v) => ({ ...v, ...otelCustomizer });
            }
        }
        return startWithTelemetry({
            name,
            rootDirectory,
            service: absoluteEntrypoint,
            codepath,
            version,
            customizer: otelCustomizer,
        });
    }
    // This needs to be required for TS on-the-fly to work
    const impl = await import(absoluteEntrypoint);
    const opts = {
        name,
        version,
        rootDirectory,
        service: impl.default || impl.service,
        codepath,
    };
    const { startApp, listen } = await import('./express-app/app.js');
    const app = await startApp(opts);
    const server = argv?.nobind ? undefined : await listen(app);
    return { server, app, codepath };
}
export function bootstrapCli(argv) {
    return bootstrap({
        nobind: true,
        ...argv,
    });
}
//# sourceMappingURL=bootstrap.js.map