/**
 * 검색 랭킹 가중치 설정 로더
 * TOML 파일에서 검색 랭킹 가중치를 로드하고 검증합니다.
 */
import { join, resolve } from 'path';
import { existsSync } from 'fs';
import { loadTOMLConfig, mergeWithDefaults, validateConfig, getCachedConfig, clearConfigCacheByPrefix, findProjectRoot } from './config-loader-utils.js';
const DEFAULT_CONFIG = {
    ranking_weights: {
        alpha: 0.45,
        beta: 0.20,
        gamma: 0.20,
        delta: 0.10,
        zeta: 0.15,
        epsilon: 0.10,
        theta: 0.1,
        zeta_fb: 0.05
    },
    relation_weights: {
        max_relations: 5
    }
};
/**
 * 로드에 사용할 TOML 경로 (캐시 키와 동일 규칙).
 */
function resolveRankingWeightsFilePath(configPath) {
    if (configPath !== undefined) {
        return resolve(configPath);
    }
    const projectRoot = findProjectRoot();
    let defaultPath = join(projectRoot, 'config', 'ranking-weights.toml');
    const distConfigPath = join(projectRoot, 'dist', 'config', 'ranking-weights.toml');
    const envPath = process.env.MEMENTO_RANKING_WEIGHTS_PATH;
    if (envPath && existsSync(envPath)) {
        defaultPath = envPath;
    }
    else if (!existsSync(defaultPath) && existsSync(distConfigPath)) {
        defaultPath = distConfigPath;
    }
    return resolve(defaultPath);
}
/**
 * TOML 파일에서 검색 랭킹 가중치 설정을 로드합니다.
 * @param configPath TOML 설정 파일 경로 (기본값: config/ranking-weights.toml)
 * @returns 검색 랭킹 가중치 설정 객체
 * @throws 설정 파일을 읽을 수 없거나 파싱에 실패한 경우
 */
export function loadRankingWeights(configPath) {
    const path = resolveRankingWeightsFilePath(configPath);
    try {
        // 공통 로더 유틸리티 사용
        const parsed = loadTOMLConfig(path, DEFAULT_CONFIG);
        // 기본값과 병합
        const config = mergeWithDefaults(parsed, DEFAULT_CONFIG);
        // 값 검증 (공통 검증 로직 사용)
        const validationSchema = {
            'ranking_weights.alpha': { type: 'number', min: 0, max: 1 },
            'ranking_weights.beta': { type: 'number', min: 0, max: 1 },
            'ranking_weights.gamma': { type: 'number', min: 0, max: 1 },
            'ranking_weights.delta': { type: 'number', min: 0, max: 1 },
            'ranking_weights.zeta': { type: 'number', min: 0, max: 1 },
            'ranking_weights.epsilon': { type: 'number', min: 0, max: 1 },
            'ranking_weights.theta': { type: 'number', min: 0, max: 1 },
            'ranking_weights.zeta_fb': { type: 'number', min: 0, max: 1 },
            'relation_weights.max_relations': { type: 'number', min: 1 }
        };
        // 중첩 객체를 평탄화하여 검증
        const flatConfig = {
            'ranking_weights.alpha': config.ranking_weights.alpha,
            'ranking_weights.beta': config.ranking_weights.beta,
            'ranking_weights.gamma': config.ranking_weights.gamma,
            'ranking_weights.delta': config.ranking_weights.delta,
            'ranking_weights.zeta': config.ranking_weights.zeta,
            'ranking_weights.epsilon': config.ranking_weights.epsilon,
            'ranking_weights.theta': config.ranking_weights.theta ?? 0.1,
            'ranking_weights.zeta_fb': config.ranking_weights.zeta_fb ?? 0.05,
            'relation_weights.max_relations': config.relation_weights.max_relations
        };
        const validationResult = validateConfig(flatConfig, validationSchema);
        if (!validationResult.valid) {
            throw new Error(`검색 랭킹 가중치 설정 검증 실패: ${validationResult.errors.join(', ')}`);
        }
        // 기존 검증 로직도 유지 (가중치 합계 경고 등)
        validateRankingWeights(config);
        return config;
    }
    catch (error) {
        if (error instanceof Error && error.message.includes('설정 파일을 찾을 수 없습니다')) {
            // 파일이 없으면 기본값 반환
            console.warn(`[ranking-weights] 설정 파일을 찾을 수 없습니다: ${path}. 기본값을 사용합니다.`);
            return DEFAULT_CONFIG;
        }
        throw new Error(`검색 랭킹 가중치 설정 로드 실패: ${error instanceof Error ? error.message : String(error)}`);
    }
}
/**
 * 검색 랭킹 가중치 설정을 검증합니다.
 * @param config 검증할 설정 객체
 * @throws 설정 값이 유효하지 않은 경우
 */
function validateRankingWeights(config) {
    const { ranking_weights, relation_weights } = config;
    // 가중치 값 검증 (0 이상 1 이하)
    const theta = ranking_weights.theta ?? 0.1;
    const zetaFb = ranking_weights.zeta_fb ?? 0.05;
    const weights = [
        { name: 'alpha', value: ranking_weights.alpha },
        { name: 'beta', value: ranking_weights.beta },
        { name: 'gamma', value: ranking_weights.gamma },
        { name: 'delta', value: ranking_weights.delta },
        { name: 'zeta', value: ranking_weights.zeta },
        { name: 'epsilon', value: ranking_weights.epsilon },
        { name: 'theta', value: theta },
        { name: 'zeta_fb', value: zetaFb }
    ];
    for (const { name, value } of weights) {
        if (!Number.isFinite(value) || value < 0 || value > 1) {
            throw new Error(`가중치 ${name}는 0 이상 1 이하의 숫자여야 합니다. 현재 값: ${value}`);
        }
    }
    // max_relations 검증 (양수)
    if (!Number.isFinite(relation_weights.max_relations) || relation_weights.max_relations <= 0) {
        throw new Error(`max_relations는 양수여야 합니다. 현재 값: ${relation_weights.max_relations}`);
    }
    // 가중치 합계 검증 (선택적: 합계가 1.0에 가까운지 확인)
    const sum = weights.reduce((acc, { value }) => acc + value, 0);
    if (sum > 1.5) {
        console.warn(`[ranking-weights] 가중치 합계(${sum.toFixed(2)})가 1.5를 초과합니다. 정규화를 권장합니다.`);
    }
}
/**
 * 검색 랭킹 가중치 설정을 가져옵니다 (캐싱됨).
 * @param configPath TOML 설정 파일 경로
 * @returns 검색 랭킹 가중치 설정 객체
 */
export function getRankingWeights(configPath) {
    const cacheKey = `ranking-weights:${resolveRankingWeightsFilePath(configPath)}`;
    return getCachedConfig(cacheKey, () => loadRankingWeights(configPath));
}
/**
 * 캐시된 설정을 초기화합니다 (테스트용).
 */
export function resetRankingWeightsCache() {
    clearConfigCacheByPrefix('ranking-weights:');
}
//# sourceMappingURL=ranking-weights-loader.js.map