"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenLimitExceededError = exports.ConfidenceTooLowError = exports.LanguageNotSupportedError = exports.NLPError = exports.NLPService = exports.TextPreprocessor = exports.NLPConfigSchema = void 0;
const tsyringe_1 = require("tsyringe");
const zod_1 = require("zod");
const openai_service_1 = require("../ai/openai.service");
const langchain_service_1 = require("../ai/langchain.service");
const text_parser_service_1 = require("./parsers/text-parser.service");
const entity_extractor_service_1 = require("./extractors/entity-extractor.service");
const task_classifier_service_1 = require("./classifiers/task-classifier.service");
const structured_data_service_1 = require("./generators/structured-data.service");
const language_detector_service_1 = require("./language-detector.service");
const translation_service_1 = require("./translation.service");
/**
 * NLP Pipeline Configuration
 */
exports.NLPConfigSchema = zod_1.z.object({
    enableCaching: zod_1.z.boolean().default(true),
    cacheMaxAge: zod_1.z.number().default(3600000), // 1 hour
    maxTokensPerRequest: zod_1.z.number().default(2000),
    defaultLanguage: zod_1.z.string().default('en'),
    supportedLanguages: zod_1.z.array(zod_1.z.string()).default(['en', 'es', 'fr', 'de']),
    confidenceThreshold: zod_1.z.number().min(0).max(1).default(0.7),
});
/**
 * Text preprocessing utilities
 */
class TextPreprocessor {
    /**
     * Clean and normalize input text
     */
    static preprocess(text) {
        // Remove excessive whitespace
        let cleaned = text.replace(/\s+/g, ' ').trim();
        // Normalize quotes
        cleaned = cleaned.replace(/['']/g, "'").replace(/[""]/g, '"');
        // Fix common typos and standardize punctuation
        cleaned = cleaned.replace(/\s+([.,!?;:])/g, '$1');
        cleaned = cleaned.replace(/([.,!?;:])\s*/g, '$1 ');
        // Ensure sentences end with proper punctuation
        if (!/[.!?]$/.test(cleaned)) {
            cleaned += '.';
        }
        return cleaned.trim();
    }
    /**
     * Split text into sentences
     */
    static segmentSentences(text) {
        // Advanced sentence splitting that handles abbreviations
        const sentences = text.match(/[^.!?]+[.!?]+/g) || [text];
        return sentences.map(s => s.trim()).filter(s => s.length > 0);
    }
    /**
     * Extract potential keywords
     */
    static extractKeywords(text) {
        const stopWords = new Set([
            'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
            'of', 'with', 'by', 'from', 'as', 'is', 'was', 'are', 'were', 'be',
            'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
            'should', 'may', 'might', 'must', 'can', 'could', 'shall', 'should',
            'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we',
            'they', 'what', 'which', 'who', 'when', 'where', 'why', 'how'
        ]);
        const words = text.toLowerCase()
            .replace(/[^\w\s]/g, ' ')
            .split(/\s+/)
            .filter(word => word.length > 2 && !stopWords.has(word));
        // Count word frequency
        const wordFreq = new Map();
        words.forEach(word => {
            wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
        });
        // Return top keywords by frequency
        return Array.from(wordFreq.entries())
            .sort((a, b) => b[1] - a[1])
            .slice(0, 10)
            .map(([word]) => word);
    }
}
exports.TextPreprocessor = TextPreprocessor;
/**
 * Main NLP Service for processing natural language input
 */
let NLPService = class NLPService {
    constructor(textParser, entityExtractor, taskClassifier, structuredDataGenerator, openAIService, langChainService, languageDetector, translationService) {
        this.textParser = textParser;
        this.entityExtractor = entityExtractor;
        this.taskClassifier = taskClassifier;
        this.structuredDataGenerator = structuredDataGenerator;
        this.openAIService = openAIService;
        this.langChainService = langChainService;
        this.languageDetector = languageDetector;
        this.translationService = translationService;
        this.cache = new Map();
        this.config = this.loadConfig();
    }
    /**
     * Load NLP configuration from environment
     */
    loadConfig() {
        return exports.NLPConfigSchema.parse({
            enableCaching: process.env.NLP_ENABLE_CACHING !== 'false',
            cacheMaxAge: parseInt(process.env.NLP_CACHE_MAX_AGE || '3600000'),
            maxTokensPerRequest: parseInt(process.env.NLP_MAX_TOKENS || '2000'),
            defaultLanguage: process.env.NLP_DEFAULT_LANGUAGE || 'en',
            supportedLanguages: process.env.NLP_SUPPORTED_LANGUAGES?.split(',') || ['en', 'es', 'fr', 'de'],
            confidenceThreshold: parseFloat(process.env.NLP_CONFIDENCE_THRESHOLD || '0.7'),
        });
    }
    /**
     * Process natural language input through the full NLP pipeline
     */
    async processText(input) {
        const startTime = Date.now();
        const errors = [];
        try {
            // Check cache first
            const cacheKey = this.getCacheKey(input);
            if (this.config.enableCaching && this.cache.has(cacheKey)) {
                const cached = this.cache.get(cacheKey);
                if (Date.now() - cached.processingTime < this.config.cacheMaxAge) {
                    return { ...cached, processingTime: Date.now() - startTime };
                }
            }
            // Preprocess text
            const preprocessedText = TextPreprocessor.preprocess(input.text);
            const keywords = TextPreprocessor.extractKeywords(preprocessedText);
            // Detect language if not provided using the dedicated service
            const languageDetection = input.language
                ? { language: input.language, confidence: 1.0 }
                : await this.languageDetector.detectLanguage(preprocessedText);
            const language = languageDetection.language;
            // Apply locale-specific rules if not English
            let processedText = preprocessedText;
            let extractedLocaleTerms = new Map();
            if (language !== 'en') {
                const localeResult = this.translationService.applyLocaleRules(preprocessedText, language);
                processedText = localeResult.normalizedText;
                extractedLocaleTerms = localeResult.extractedTerms;
            }
            // Parse text structure
            const parsedText = await this.textParser.parse({
                text: processedText,
                language,
                keywords,
            });
            // Extract entities
            const entities = await this.entityExtractor.extract({
                text: processedText,
                parsedData: parsedText,
                language,
                context: { ...input.context, localeTerms: Object.fromEntries(extractedLocaleTerms) },
            });
            // Classify task
            const classification = await this.taskClassifier.classify({
                text: processedText,
                entities,
                language,
                keywords,
            });
            // Generate structured data
            const structuredData = await this.structuredDataGenerator.generate({
                text: processedText,
                entities,
                classification,
                context: { ...input.context, localeTerms: Object.fromEntries(extractedLocaleTerms) },
                projectId: input.projectId,
            });
            // Calculate overall confidence
            const overallConfidence = this.calculateOverallConfidence(entities.confidence || 0, classification.confidence || 0);
            const result = {
                success: overallConfidence >= this.config.confidenceThreshold,
                entities,
                classification,
                structuredData,
                language,
                processingTime: Date.now() - startTime,
                tokensUsed: parsedText.tokensUsed || 0,
                errors: errors.length > 0 ? errors : undefined,
            };
            // Cache successful results
            if (result.success && this.config.enableCaching) {
                this.cache.set(cacheKey, result);
            }
            return result;
        }
        catch (error) {
            console.error('NLP processing error:', error);
            errors.push(error instanceof Error ? error.message : 'Unknown error');
            return {
                success: false,
                entities: {},
                classification: {},
                structuredData: null,
                language: input.language || this.config.defaultLanguage,
                processingTime: Date.now() - startTime,
                errors,
            };
        }
    }
    /**
     * Calculate overall confidence score
     */
    calculateOverallConfidence(entityConfidence, classificationConfidence) {
        // Weighted average with more weight on entity extraction
        return (entityConfidence * 0.6 + classificationConfidence * 0.4);
    }
    /**
     * Generate cache key for input
     */
    getCacheKey(input) {
        const key = `${input.text.substring(0, 100)}_${input.language || 'auto'}_${input.projectId || 'none'}`;
        return Buffer.from(key).toString('base64');
    }
    /**
     * Clear cache (useful for testing or memory management)
     */
    clearCache() {
        this.cache.clear();
    }
    /**
     * Get cache statistics
     */
    getCacheStats() {
        return {
            size: this.cache.size,
            maxAge: this.config.cacheMaxAge,
        };
    }
    /**
     * Process text with translation to English if needed
     */
    async processTextWithTranslation(input) {
        // Detect language
        const languageDetection = await this.languageDetector.detectLanguage(input.text);
        // If not English and high confidence, translate to English first
        if (languageDetection.language !== 'en' && languageDetection.confidence > 0.7) {
            const translation = await this.translationService.translate({
                text: input.text,
                sourceLanguage: languageDetection.language,
                targetLanguage: 'en',
                preserveFormatting: true,
            });
            // Process the translated text
            const result = await this.processText({
                ...input,
                text: translation.translatedText,
                language: 'en',
                context: {
                    ...input.context,
                    originalLanguage: languageDetection.language,
                    originalText: input.text,
                },
            });
            // Add translation metadata to result
            return {
                ...result,
                language: languageDetection.language,
                structuredData: {
                    ...result.structuredData,
                    translatedFrom: languageDetection.language,
                    originalText: input.text,
                },
            };
        }
        // Process directly if already in English or low confidence
        return this.processText(input);
    }
    /**
     * Get supported languages
     */
    getSupportedLanguages() {
        return this.languageDetector.getSupportedLanguages().map(lang => lang.code);
    }
    /**
     * Check if a language is supported
     */
    isLanguageSupported(languageCode) {
        return this.languageDetector.isLanguageSupported(languageCode);
    }
};
exports.NLPService = NLPService;
exports.NLPService = NLPService = __decorate([
    (0, tsyringe_1.injectable)(),
    __metadata("design:paramtypes", [text_parser_service_1.TextParserService,
        entity_extractor_service_1.EntityExtractorService,
        task_classifier_service_1.TaskClassifierService,
        structured_data_service_1.StructuredDataGeneratorService,
        openai_service_1.OpenAIService,
        langchain_service_1.LangChainService,
        language_detector_service_1.LanguageDetectorService,
        translation_service_1.TranslationService])
], NLPService);
/**
 * NLP-specific error classes
 */
class NLPError extends Error {
    constructor(message, code, details) {
        super(message);
        this.code = code;
        this.details = details;
        this.name = 'NLPError';
    }
}
exports.NLPError = NLPError;
class LanguageNotSupportedError extends NLPError {
    constructor(language) {
        super(`Language '${language}' is not supported`, 'LANGUAGE_NOT_SUPPORTED', { language });
    }
}
exports.LanguageNotSupportedError = LanguageNotSupportedError;
class ConfidenceTooLowError extends NLPError {
    constructor(confidence, threshold) {
        super(`Confidence score ${confidence} is below threshold ${threshold}`, 'CONFIDENCE_TOO_LOW', { confidence, threshold });
    }
}
exports.ConfidenceTooLowError = ConfidenceTooLowError;
class TokenLimitExceededError extends NLPError {
    constructor(tokens, limit) {
        super(`Token count ${tokens} exceeds limit ${limit}`, 'TOKEN_LIMIT_EXCEEDED', { tokens, limit });
    }
}
exports.TokenLimitExceededError = TokenLimitExceededError;
//# sourceMappingURL=nlp.service.js.map