import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { tmpdir } from 'node:os';
import { stringify as stringifyYaml } from 'yaml';
const require = createRequire(import.meta.url);
const { execFileSync: execFileSyncRuntime } = require('node:child_process');
function executeRuntimeLoader(input) {
    const stdout = execFileSyncRuntime(process.execPath, ['--input-type=module', '-e', TRACED_CONFIG_RUNTIME_SCRIPT], {
        cwd: TAKT_PACKAGE_ROOT,
        env: process.env,
        input: JSON.stringify(input),
        encoding: 'utf-8',
    });
    return JSON.parse(stdout.trim());
}
function serializeSchema(schema) {
    const serialized = {};
    for (const [key, entry] of Object.entries(schema)) {
        let format;
        if (entry.format === String)
            format = 'string';
        else if (entry.format === Number)
            format = 'number';
        else if (entry.format === Boolean)
            format = 'boolean';
        else if (entry.format === 'json')
            format = 'json';
        else
            format = undefined;
        serialized[key] = {
            default: entry.default,
            doc: entry.doc,
            format,
            env: entry.env,
            sources: entry.sources,
        };
    }
    return serialized;
}
function coerceJsonEnvValue(key, format, traced) {
    if (format !== 'json' || (traced.origin !== 'env' && traced.origin !== 'cli') || typeof traced.value !== 'string') {
        return traced;
    }
    try {
        return {
            ...traced,
            value: JSON.parse(traced.value),
        };
    }
    catch {
        throw new Error(`Invalid JSON override for ${key}`);
    }
}
function hasSchemaCollision(schemaKeys, key) {
    return schemaKeys.some((candidate) => candidate === key || candidate.startsWith(`${key}.`) || key.startsWith(`${candidate}.`));
}
function partitionSchema(schema) {
    const groups = [];
    for (const [key, entry] of Object.entries(schema)) {
        const group = groups.find((candidate) => !hasSchemaCollision(Object.keys(candidate), key));
        if (group) {
            group[key] = entry;
            continue;
        }
        groups.push({ [key]: entry });
    }
    return groups;
}
const TRACED_CONFIG_RUNTIME_SCRIPT = `
import { readFileSync } from 'node:fs';

const input = JSON.parse(readFileSync(0, 'utf8'));
const tracedConfigModuleUrl = import.meta.resolve('traced-config');
const { tracedConfig } = await import(tracedConfigModuleUrl);
const traceEntries = [];
for (const schemaGroup of input.schemaGroups) {
  const schema = {};
  for (const [key, entry] of Object.entries(schemaGroup)) {
    let format;
    if (entry.format === 'string') format = String;
    else if (entry.format === 'number') format = Number;
    else if (entry.format === 'boolean') format = Boolean;
    else if (entry.format === 'json') format = 'json';
    schema[key] = {
      default: entry.default,
      doc: entry.doc,
      format,
      env: entry.env,
      sources: entry.sources,
    };
  }

  const config = tracedConfig({
    defaultSources: { env: false, cli: false },
    schema,
  });

  if (input.tempConfigPath) {
    await config.loadFile([{ path: input.tempConfigPath, label: input.fileOrigin }]);
  }

  for (const key of Object.keys(schema)) {
    traceEntries.push([key, config.getTraced(key)]);
  }
}
process.stdout.write(JSON.stringify({ traceEntries }));
`;
const TAKT_PACKAGE_ROOT = dirname(fileURLToPath(new URL('../../../../package.json', import.meta.url)));
export function loadTraceEntriesViaRuntime(schema, fileOrigin, parsedConfig) {
    const tempDir = mkdtempSync(join(tmpdir(), 'takt-traced-config-'));
    try {
        const tempConfigPath = Object.keys(parsedConfig).length > 0
            ? join(tempDir, 'config.yaml')
            : undefined;
        if (tempConfigPath) {
            writeFileSync(tempConfigPath, stringifyYaml(parsedConfig), 'utf-8');
        }
        const input = {
            schemaGroups: partitionSchema(schema).map((schemaGroup) => serializeSchema(schemaGroup)),
            fileOrigin,
            tempConfigPath,
        };
        const result = executeRuntimeLoader(input);
        const traceEntries = new Map();
        for (const [key, traced] of result.traceEntries) {
            const entry = input.schemaGroups.find((group) => key in group)?.[key];
            if (!entry) {
                throw new Error(`Missing traced-config schema entry for ${key}`);
            }
            traceEntries.set(key, coerceJsonEnvValue(key, entry.format, traced));
        }
        return traceEntries;
    }
    finally {
        rmSync(tempDir, { recursive: true, force: true });
    }
}
//# sourceMappingURL=tracedConfigRuntimeBridge.js.map