"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PreferencesResolver = void 0;
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const config_storage_1 = require("../lib/config-storage");
const preferences_schema_1 = require("./preferences-schema");
const PROJECT_FILE = 'flui.config.json';
/**
 * Resolves user preferences across all configured layers.
 *
 * Cascade (first hit wins):
 *   explicit value > env var > project-local > user-global (active profile) > default > missing
 *
 * The project-local file may only override keys whose schema declares
 * `projectOverridable: true`. Secret values (tokens, apiKey) are never read here.
 */
class PreferencesResolver {
    constructor(storage = new config_storage_1.ConfigStorage(), cwd = process.cwd()) {
        this.storage = storage;
        this.cwd = cwd;
    }
    resolve(key, explicit) {
        const def = preferences_schema_1.PREFERENCES[key];
        if (explicit !== undefined && explicit !== null && explicit !== '') {
            return { key, value: explicit, source: 'explicit' };
        }
        const envValue = process.env[def.envVar];
        if (envValue !== undefined && envValue !== '') {
            return { key, value: envValue, source: 'env' };
        }
        if (def.projectOverridable) {
            const projectValue = this.readProjectFile()?.[key];
            if (projectValue !== undefined && projectValue !== '') {
                return { key, value: projectValue, source: 'project' };
            }
        }
        const userValue = this.storage.getPreference(key);
        if (userValue !== undefined && userValue !== null && userValue !== '') {
            return { key, value: userValue, source: 'user' };
        }
        if (def.defaultValue !== undefined) {
            return {
                key,
                value: def.defaultValue,
                source: 'default',
            };
        }
        return { key, value: null, source: 'missing' };
    }
    /**
     * Resolve every key declared in the schema. Useful for `flui pref` listing.
     */
    resolveAll() {
        return Object.keys(preferences_schema_1.PREFERENCES).map((k) => this.resolve(k));
    }
    /**
     * Validate a candidate value against the schema. Returns null when ok.
     */
    static validate(key, value) {
        const def = preferences_schema_1.PREFERENCES[key];
        if (def.allowedValues && !def.allowedValues.includes(value)) {
            return `Allowed values: ${def.allowedValues.join(', ')}`;
        }
        if (def.validate) {
            return def.validate(value);
        }
        return null;
    }
    projectFilePath() {
        return (0, node_path_1.join)(this.cwd, PROJECT_FILE);
    }
    /**
     * Lazy-load the project-local file once per resolver instance.
     * Returns null when missing or unreadable; throws only on malformed JSON
     * (so config errors don't fail silently).
     */
    readProjectFile() {
        if (this.projectConfigCache !== undefined) {
            return this.projectConfigCache;
        }
        const path = this.projectFilePath();
        if (!(0, node_fs_1.existsSync)(path)) {
            this.projectConfigCache = null;
            return null;
        }
        try {
            const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf-8'));
            if (typeof parsed !== 'object' || parsed === null) {
                throw new Error('expected a JSON object at the root');
            }
            this.projectConfigCache = parsed;
            return this.projectConfigCache;
        }
        catch (err) {
            throw new Error(`Failed to parse project config ${path}: ${err.message}`);
        }
    }
}
exports.PreferencesResolver = PreferencesResolver;
