/**
 * 쿼리 필터 서비스 인터페이스 및 구현
 * Phase 2.4: anchor-search-service.ts 분리
 */
import { logger } from '../../../../shared/utils/logger.js';
import { UnifiedEmbeddingService } from '../../../embedding/services/unified-embedding-service.js';
/**
 * 쿼리 필터 서비스 구현
 */
export class QueryFilterService {
    cacheService;
    queryEmbeddingService;
    constructor(cacheService) {
        this.cacheService = cacheService;
        this.queryEmbeddingService = new UnifiedEmbeddingService();
    }
    /**
     * 쿼리 기반 필터링
     */
    async filterByQuery(query, results, _provider) {
        if (results.length === 0) {
            return results;
        }
        try {
            // 쿼리 임베딩 생성
            const queryEmbeddingResult = await this.queryEmbeddingService.generateEmbedding(query);
            if (!queryEmbeddingResult || !queryEmbeddingResult.embedding) {
                logger.warn('Query embedding generation failed, skipping filter');
                return results;
            }
            const queryEmbedding = queryEmbeddingResult.embedding;
            // 각 결과 메모리의 임베딩 조회 및 쿼리 유사도 계산
            const resultsWithQuerySimilarity = await Promise.all(results.map(async (result) => {
                try {
                    const memoryEmbedding = await this.cacheService.getAnchorEmbedding(result.memory_id);
                    if (!memoryEmbedding || !memoryEmbedding.embedding) {
                        return {
                            ...result,
                            query_similarity: 0,
                            combined_similarity: result.similarity * 0.5
                        };
                    }
                    // 쿼리 임베딩과 메모리 임베딩 간 유사도 계산
                    let querySim = 0;
                    if (queryEmbedding.length === memoryEmbedding.embedding.length) {
                        querySim = this.cosineSimilarity(queryEmbedding, memoryEmbedding.embedding);
                    }
                    else {
                        // 차원이 다르면 텍스트 기반 간단한 매칭
                        querySim = this.calculateTextSimilarity(query, result.content);
                    }
                    const baseRankingScore = this.calculateBaseRankingScore(result.similarity, result.hop_distance, result.importance);
                    const combinedSimilarity = baseRankingScore * 0.6 + querySim * 0.4;
                    return {
                        ...result,
                        query_similarity: querySim,
                        combined_similarity: combinedSimilarity
                    };
                }
                catch (error) {
                    logger.error('Query filtering failed for memory', {
                        memoryId: result.memory_id,
                        error: error instanceof Error ? error.message : String(error)
                    });
                    return {
                        ...result,
                        query_similarity: 0,
                        combined_similarity: result.similarity * 0.5
                    };
                }
            }));
            // 쿼리 유사도 임계값 적용
            const queryThreshold = 0.3;
            const filtered = resultsWithQuerySimilarity.filter(r => r.query_similarity >= queryThreshold || r.combined_similarity >= 0.5);
            // 결합 유사도 기준으로 재정렬
            filtered.sort((a, b) => {
                if (Math.abs(a.combined_similarity - b.combined_similarity) < 0.001) {
                    return a.hop_distance - b.hop_distance;
                }
                return b.combined_similarity - a.combined_similarity;
            });
            // 원본 similarity를 combined_similarity로 업데이트하여 반환
            return filtered.map(r => ({
                ...r,
                similarity: r.combined_similarity
            }));
        }
        catch (error) {
            logger.error('Query-based filtering failed', {
                error: error instanceof Error ? error.message : String(error)
            });
            return results;
        }
    }
    /**
     * 코사인 유사도 계산
     */
    cosineSimilarity(a, b) {
        if (a.length !== b.length) {
            throw new Error('벡터 차원이 일치하지 않습니다');
        }
        let dotProduct = 0;
        let normA = 0;
        let normB = 0;
        for (let i = 0; i < a.length; i++) {
            const aVal = a[i] ?? 0;
            const bVal = b[i] ?? 0;
            dotProduct += aVal * bVal;
            normA += aVal * aVal;
            normB += bVal * bVal;
        }
        const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
        return magnitude === 0 ? 0 : dotProduct / magnitude;
    }
    /**
     * 텍스트 기반 유사도 계산
     */
    calculateTextSimilarity(query, content) {
        const queryLower = query.toLowerCase();
        const contentLower = content.toLowerCase();
        const queryWords = queryLower.split(/\s+/);
        const matchCount = queryWords.filter(word => contentLower.includes(word)).length;
        return matchCount / Math.max(queryWords.length, 1);
    }
    /**
     * 기본 랭킹 점수 계산
     */
    calculateBaseRankingScore(similarity, hopDistance, importance = 0.5) {
        const hopDecayFactor = 1.0 / (1.0 + (hopDistance - 1) * 0.3);
        const anchorProximityBoost = hopDistance === 1 ? 1.2 : 1.0;
        const importanceWeight = 0.1;
        const importanceBoost = 1.0 + (importance - 0.5) * importanceWeight;
        return Math.min(1.0, similarity * hopDecayFactor * anchorProximityBoost * importanceBoost);
    }
}
//# sourceMappingURL=query-filter-service.js.map