/**
 * Quality Evaluator
 *
 * 품질 평가 서비스
 *
 * 주요 기능:
 * - 임계값 비교 및 품질 평가
 * - 상태 결정: pass/warning/fail
 * - 경고 정보 생성
 *
 * PRD FR-1.1: Evaluator 역할 - 임계값 비교 및 품질 평가
 * PRD FR-4.2: 품질 측정 시 임계값을 검증해야 함
 */
import Database from 'better-sqlite3';
import fsPromises from 'fs/promises';
import path from 'path';
import { QualityThresholdManager } from './quality-threshold-manager.js';
import { logger } from '../../../../shared/utils/logger.js';
/**
 * Quality Evaluator
 *
 * PRD FR-1.1: Evaluator 역할 - 임계값 비교 및 품질 평가
 */
export class QualityEvaluator {
    db;
    thresholdManager;
    constructor(db) {
        this.db = db;
        if (!db) {
            throw new Error('Database instance is required');
        }
        this.thresholdManager = new QualityThresholdManager(db);
    }
    /**
     * 단일 지표 평가
     *
     * @param namespace - 네임스페이스
     * @param key - 지표 키
     * @param value - 측정값
     * @param context - 컨텍스트 (기본값: 'default')
     * @returns 지표 평가 결과
     */
    evaluateMetric(namespace, key, value, context = 'default') {
        const validation = this.thresholdManager.validateThreshold(namespace, key, value, context);
        let difference = null;
        if (validation.threshold) {
            if (validation.threshold.threshold_type === 'min') {
                // min 타입: value - threshold_value (양수면 여유, 음수면 부족)
                difference = value - validation.threshold.threshold_value;
            }
            else if (validation.threshold.threshold_type === 'max') {
                // max 타입: threshold_value - value (양수면 여유, 음수면 부족)
                difference = validation.threshold.threshold_value - value;
            }
        }
        return {
            namespace,
            key,
            value,
            threshold: validation.threshold,
            passed: validation.passed,
            difference,
            message: validation.message
        };
    }
    /**
     * 품질 지표 평가
     *
     * PRD FR-4.2: 품질 측정 시 임계값을 검증해야 함
     *
     * 벡터 차원 불일치 해결 후 재평가:
     * - 벡터 차원 불일치 문제를 해결한 후 품질 지표가 개선되었을 수 있음
     * - precision_at_5=0인 경우는 벡터 차원 불일치로 인한 완전 실패일 가능성이 높음
     * - 벡터 차원 불일치 해결 후에는 재측정하여 개선 여부 확인 필요
     *
     * @param metrics - 수집된 품질 지표
     * @param context - 컨텍스트 (기본값: 'default')
     * @returns 품질 평가 결과
     */
    async evaluateMetrics(metrics, context = 'default') {
        const metricResults = [];
        const warnings = [];
        // 각 지표를 평가
        for (const [key, value] of Object.entries(metrics.metrics)) {
            const result = this.evaluateMetric(metrics.namespace, key, value, context);
            metricResults.push(result);
            // 임계값 미달 시 경고 추가
            if (!result.passed && result.threshold) {
                warnings.push({
                    metric_key: key,
                    value,
                    threshold_value: result.threshold.threshold_value,
                    difference: result.difference || 0,
                    message: result.message
                });
            }
        }
        // 상태 결정
        const passedCount = metricResults.filter(r => r.passed).length;
        const failedCount = metricResults.filter(r => !r.passed).length;
        const totalCount = metricResults.length;
        // 상태 결정 로직:
        // - pass: 모든 지표가 통과
        // - warning: 일부 지표가 실패했지만 심각하지 않음 (임계값이 설정되지 않은 경우는 제외)
        // - fail: 중요한 지표가 실패 (임계값이 설정된 지표 중 실패)
        let status = 'pass';
        if (failedCount > 0) {
            // 임계값이 설정된 지표 중 실패한 것이 있으면 fail
            const failedWithThreshold = metricResults.filter(r => !r.passed && r.threshold !== null).length;
            if (failedWithThreshold > 0) {
                status = 'fail';
            }
            else {
                // 임계값이 설정되지 않은 지표만 실패한 경우는 warning
                status = 'warning';
            }
        }
        // 평가 결과 생성
        const evaluationResult = {
            namespace: metrics.namespace,
            context,
            status,
            metricResults,
            passedCount,
            failedCount,
            totalCount,
            warnings,
            evaluated_at: new Date().toISOString()
        };
        // PRD FR-4.2: 경고 로그 기록
        if (warnings.length > 0) {
            logger.warn(`품질 저하 감지: ${metrics.namespace} (${context})`, {
                namespace: metrics.namespace,
                context,
                warnings: warnings.map(w => ({
                    metric: w.metric_key,
                    value: w.value,
                    threshold: w.threshold_value,
                    difference: w.difference
                }))
            });
            // PRD FR-4.3: 구조화된 JSON 로그 파일 기록
            await this.logWarningToFile(evaluationResult);
        }
        return evaluationResult;
    }
    /**
     * 여러 네임스페이스의 품질 지표 평가
     *
     * @param metricsList - 수집된 품질 지표 목록
     * @param context - 컨텍스트 (기본값: 'default')
     * @returns 품질 평가 결과 목록
     */
    async evaluateAllMetrics(metricsList, context = 'default') {
        return Promise.all(metricsList.map(metrics => this.evaluateMetrics(metrics, context)));
    }
    /**
     * 전체 상태 결정
     *
     * 여러 네임스페이스의 평가 결과를 종합하여 전체 상태를 결정
     *
     * @param evaluationResults - 평가 결과 목록
     * @returns 전체 상태: 'pass', 'warning', 'fail'
     */
    determineOverallStatus(evaluationResults) {
        if (evaluationResults.length === 0) {
            return 'pass';
        }
        // fail이 하나라도 있으면 전체 fail
        if (evaluationResults.some(r => r.status === 'fail')) {
            return 'fail';
        }
        // warning이 하나라도 있으면 전체 warning
        if (evaluationResults.some(r => r.status === 'warning')) {
            return 'warning';
        }
        // 모두 pass면 전체 pass
        return 'pass';
    }
    /**
     * 경고 정보 생성
     *
     * PRD FR-4.2: 경고 로그에 상세 정보 포함 (지표명, 측정값, 임계값, 차이)
     *
     * @param evaluationResult - 평가 결과
     * @returns 경고 정보 (JSON 형식)
     */
    generateWarningInfo(evaluationResult) {
        if (evaluationResult.warnings.length === 0) {
            return JSON.stringify({ warnings: [] });
        }
        const warningInfo = {
            namespace: evaluationResult.namespace,
            context: evaluationResult.context,
            status: evaluationResult.status,
            evaluated_at: evaluationResult.evaluated_at,
            warnings: evaluationResult.warnings.map(w => ({
                metric_key: w.metric_key,
                value: w.value,
                threshold_value: w.threshold_value,
                threshold_type: evaluationResult.metricResults.find(r => r.key === w.metric_key)?.threshold?.threshold_type || 'unknown',
                difference: w.difference,
                message: w.message
            }))
        };
        return JSON.stringify(warningInfo, null, 2);
    }
    /**
     * 경고 로그를 파일에 기록
     *
     * PRD FR-4.3: 품질 저하 발생 시 구조화된 JSON 로그 기록
     * `logs/quality-warnings-{date}.log` 형식으로 저장
     *
     * @param evaluationResult - 평가 결과
     */
    async logWarningToFile(evaluationResult) {
        try {
            const logDir = path.join(process.cwd(), 'logs');
            // 로그 디렉토리 생성
            try {
                await fsPromises.access(logDir);
            }
            catch {
                await fsPromises.mkdir(logDir, { recursive: true });
            }
            // 날짜별 로그 파일명 생성 (YYYY-MM-DD 형식)
            const today = new Date().toISOString().split('T')[0];
            const logFilePath = path.join(logDir, `quality-warnings-${today}.log`);
            // 구조화된 JSON 로그 엔트리 생성
            const logEntry = {
                timestamp: evaluationResult.evaluated_at,
                namespace: evaluationResult.namespace,
                context: evaluationResult.context,
                status: evaluationResult.status,
                passed_count: evaluationResult.passedCount,
                failed_count: evaluationResult.failedCount,
                total_count: evaluationResult.totalCount,
                warnings: evaluationResult.warnings.map(w => ({
                    metric_key: w.metric_key,
                    value: w.value,
                    threshold_value: w.threshold_value,
                    threshold_type: evaluationResult.metricResults.find(r => r.key === w.metric_key)?.threshold?.threshold_type || 'unknown',
                    difference: w.difference,
                    message: w.message
                }))
            };
            // JSON Lines 형식으로 파일에 추가
            const logLine = JSON.stringify(logEntry) + '\n';
            await fsPromises.appendFile(logFilePath, logLine, 'utf-8');
        }
        catch (error) {
            // 파일 로깅 실패는 콘솔 로거에 위임
            logger.error('품질 경고 로그 파일 기록 실패', {
                namespace: evaluationResult.namespace,
                context: evaluationResult.context,
                error: error instanceof Error ? error.message : String(error)
            });
        }
    }
}
//# sourceMappingURL=quality-evaluator.js.map