/**
 * Unified config file loader — resolves TS/JS/YAML/JSON with format priority.
 *
 * Provides a single `loadConfigFile()` function that replaces the scattered
 * `readFileSync + load(raw)` pattern throughout the pipeline. Checks for
 * TypeScript/JavaScript config files first (via jiti), falling back to YAML
 * and JSON — matching the resolution order established in Phase 1.
 *
 * Priority: `.ts` > `.js` > `.yaml` > `.yml` > `.json`
 *
 * Usage:
 * ```ts
 * // Before (scattered pattern):
 * const raw = readFileSync(resolve(rootDir, "config", "models config"), "utf-8")
 * const config = load(raw) as ModelsConfig
 *
 * // After:
 * const config = loadConfigFile<ModelsConfig>("models", rootDir)
 * ```
 *
 * @see packages/eval/src/adapters/config-sources/ts-config-loader.ts — jiti loader
 * @see docs/design-docs/architecture-overhaul/typescript-configuration.md
 */
import { createRequire } from "module";
import { existsSync, readFileSync } from "fs";
import { load } from "js-yaml";
import { resolve } from "path";
import { resolveAilfAlias } from "../../adapters/config-sources/ailf-resolver.js";
/**
 * Load a config file by name, searching for TS/JS/YAML/JSON variants.
 *
 * @param name - Config name without extension (e.g., "models", "rubrics")
 * @param rootDir - Package root directory containing `config/`
 * @param options - Optional: subdirectory (default "config"), required flag
 * @returns The parsed config data
 * @throws If the file is not found (when required) or fails to parse
 */
export function loadConfigFile(name, rootDir, options) {
    const subdir = options?.subdir ?? "config";
    const baseDir = resolveVendoredSubdir(rootDir, subdir);
    const basePath = resolve(baseDir, name);
    // Priority chain: .ts > .js > .yaml > .yml > .json
    const candidates = [
        { ext: ".ts", format: "ts" },
        { ext: ".js", format: "js" },
        { ext: ".yaml", format: "yaml" },
        { ext: ".yml", format: "yaml" },
        { ext: ".json", format: "json" },
    ];
    for (const { ext, format } of candidates) {
        const filePath = basePath + ext;
        if (!existsSync(filePath))
            continue;
        if (format === "ts" || format === "js") {
            return loadTsFile(filePath, format);
        }
        if (format === "yaml") {
            return loadYamlFile(filePath);
        }
        if (format === "json") {
            return loadJsonFile(filePath);
        }
    }
    // Always throw ConfigNotFoundError so tryLoadConfigFile can catch it
    throw new ConfigNotFoundError(name, baseDir);
}
/**
 * Try to load a config file, returning null if not found.
 * Equivalent to loadConfigFile with required: false but with a cleaner API.
 */
export function tryLoadConfigFile(name, rootDir, options) {
    try {
        return loadConfigFile(name, rootDir, options);
    }
    catch (err) {
        if (err instanceof ConfigNotFoundError)
            return null;
        throw err;
    }
}
/** Sentinel error for config-not-found (distinct from parse errors) */
export class ConfigNotFoundError extends Error {
    configName;
    searchDir;
    constructor(configName, searchDir) {
        super(`Config "${configName}" not found in ${searchDir}`);
        this.configName = configName;
        this.searchDir = searchDir;
        this.name = "ConfigNotFoundError";
    }
}
// ---------------------------------------------------------------------------
// Vendored config detection
// ---------------------------------------------------------------------------
/**
 * Resolve a package subdirectory, preferring the vendored copy in dist/
 * when @sanity/ailf-core isn't directly resolvable (i.e., installed outside
 * the monorepo via npx or npm).
 *
 * The build step (bundle-workspace-deps.ts) copies config/ and tasks/ into
 * dist/ with @sanity/ailf-core imports rewritten to the _vendor/ path.
 * This function detects that situation and returns the dist/ path instead.
 *
 * @param rootDir - Package root directory (packages/eval)
 * @param subdir - Subdirectory to resolve (e.g., "config", "tasks/literacy")
 * @returns The resolved subdirectory path — either source or dist/ vendored
 */
export function resolveVendoredSubdir(rootDir, subdir) {
    if (shouldUseVendoredConfigs(rootDir)) {
        const vendoredDir = resolve(rootDir, "dist", subdir);
        if (existsSync(vendoredDir))
            return resolve(rootDir, "dist", subdir);
    }
    return resolve(rootDir, subdir);
}
let _vendoredCache;
function shouldUseVendoredConfigs(rootDir) {
    if (_vendoredCache !== undefined)
        return _vendoredCache;
    // Check if @sanity/ailf-core resolves (i.e., we're in the monorepo)
    try {
        const require = createRequire(resolve(rootDir, "package.json"));
        require.resolve("@sanity/ailf-core");
        _vendoredCache = false;
    }
    catch {
        _vendoredCache = true;
    }
    return _vendoredCache;
}
// ---------------------------------------------------------------------------
// Format-specific loaders
// ---------------------------------------------------------------------------
function loadTsFile(filePath, format) {
    // jiti supports sync loading. Use createRequire for ESM compatibility.
    const esmRequire = createRequire(import.meta.url);
    const { createJiti } = esmRequire("jiti");
    const alias = resolveAilfAlias(filePath);
    const jiti = createJiti(filePath, {
        interopDefault: true,
        ...(alias ? { alias } : {}),
    });
    const mod = jiti(filePath);
    const data = (mod?.default ?? mod);
    return { data, filePath, format };
}
function loadYamlFile(filePath) {
    const raw = readFileSync(filePath, "utf-8");
    const data = load(raw);
    return { data, filePath, format: "yaml" };
}
function loadJsonFile(filePath) {
    const raw = readFileSync(filePath, "utf-8");
    const data = JSON.parse(raw);
    return { data, filePath, format: "json" };
}
