"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.TextParserService = void 0;
const tsyringe_1 = require("tsyringe");
const openai_service_1 = require("../../ai/openai.service");
const langchain_service_1 = require("../../ai/langchain.service");
/**
 * Text Parser Service for syntactic analysis and tokenization
 */
let TextParserService = class TextParserService {
    constructor(openAIService, langChainService) {
        this.openAIService = openAIService;
        this.langChainService = langChainService;
    }
    /**
     * Parse text into structured components
     */
    async parse(input) {
        const { text, language, keywords = [] } = input;
        // Segment sentences
        const sentences = this.segmentSentences(text);
        // Tokenize each sentence
        const parsedSentences = sentences.map(sentence => this.tokenizeSentence(sentence));
        // Get parts of speech using OpenAI
        const partsOfSpeech = await this.extractPartsOfSpeech(text, language);
        // Analyze syntactic structure
        const syntacticStructure = await this.analyzeSyntacticStructure(text, parsedSentences);
        // Preserve context for multi-sentence input
        const contextualizedSentences = this.preserveContext(parsedSentences);
        return {
            originalText: text,
            sentences: contextualizedSentences,
            partsOfSpeech,
            syntacticStructure,
            language,
            keywords,
            tokensUsed: this.estimateTokens(text),
        };
    }
    /**
     * Segment text into sentences with improved handling
     */
    segmentSentences(text) {
        // Handle abbreviations and special cases
        const abbreviations = ['Dr.', 'Mr.', 'Mrs.', 'Ms.', 'Prof.', 'Sr.', 'Jr.', 'Inc.', 'Ltd.', 'Co.', 'Corp.', 'vs.', 'etc.', 'i.e.', 'e.g.'];
        let processedText = text;
        // Temporarily replace abbreviations to avoid false sentence breaks
        const replacements = new Map();
        abbreviations.forEach((abbr, index) => {
            const placeholder = `__ABBR${index}__`;
            replacements.set(placeholder, abbr);
            processedText = processedText.replace(new RegExp(abbr.replace('.', '\\.'), 'g'), placeholder);
        });
        // Split sentences on sentence-ending punctuation
        const sentencePattern = /([.!?]+[\s\n]+|[.!?]+$)/g;
        let sentences = processedText.split(sentencePattern);
        // Reconstruct sentences
        const reconstructed = [];
        for (let i = 0; i < sentences.length; i += 2) {
            if (sentences[i]) {
                const sentence = sentences[i] + (sentences[i + 1] || '');
                reconstructed.push(sentence.trim());
            }
        }
        // Restore abbreviations
        const finalSentences = reconstructed.map(sentence => {
            let restored = sentence;
            replacements.forEach((original, placeholder) => {
                restored = restored.replace(new RegExp(placeholder, 'g'), original);
            });
            return restored;
        }).filter(s => s.length > 0);
        return finalSentences.length > 0 ? finalSentences : [text];
    }
    /**
     * Tokenize a single sentence
     */
    tokenizeSentence(sentence) {
        const tokens = [];
        // Enhanced tokenization pattern
        const tokenPattern = /(\w+['']?\w*|\d+\.?\d*|[^\w\s])/g;
        let match;
        while ((match = tokenPattern.exec(sentence)) !== null) {
            const text = match[0];
            let type = 'word';
            if (/^\d+\.?\d*$/.test(text)) {
                type = 'number';
            }
            else if (/^[^\w\s]$/.test(text)) {
                type = 'punctuation';
            }
            else if (/^[^\w\d]+$/.test(text)) {
                type = 'symbol';
            }
            tokens.push({
                text,
                type,
                position: match.index,
                length: text.length,
            });
        }
        // Determine sentence type
        let sentenceType = 'declarative';
        if (sentence.endsWith('?')) {
            sentenceType = 'interrogative';
        }
        else if (sentence.endsWith('!')) {
            sentenceType = 'exclamatory';
        }
        else if (this.isImperative(sentence, tokens)) {
            sentenceType = 'imperative';
        }
        return {
            text: sentence,
            tokens,
            type: sentenceType,
        };
    }
    /**
     * Check if a sentence is imperative
     */
    isImperative(sentence, tokens) {
        const imperativeStarters = ['please', 'create', 'add', 'implement', 'build', 'develop', 'make', 'fix', 'update', 'delete', 'remove'];
        const firstWord = tokens[0]?.text.toLowerCase();
        return imperativeStarters.includes(firstWord) ||
            (sentence.toLowerCase().startsWith('please ') && tokens.length > 1);
    }
    /**
     * Extract parts of speech using OpenAI
     */
    async extractPartsOfSpeech(text, language) {
        try {
            const prompt = `Analyze the parts of speech for each significant word in this ${language} text. Return a JSON array with objects containing: word, tag (using Penn Treebank tags like NN, VB, JJ), and description.

Text: "${text}"

Return only the JSON array, no additional text.`;
            const result = await this.openAIService.complete([{ role: 'user', content: prompt }], { maxTokens: 500, temperature: 0.3 });
            try {
                const parsed = JSON.parse(result.content.trim());
                return Array.isArray(parsed) ? parsed : [];
            }
            catch {
                // Fallback to basic POS tagging
                return this.basicPOSTagging(text);
            }
        }
        catch (error) {
            console.error('POS tagging with OpenAI failed:', error);
            return this.basicPOSTagging(text);
        }
    }
    /**
     * Basic POS tagging fallback
     */
    basicPOSTagging(text) {
        const words = text.split(/\s+/);
        const commonNouns = new Set(['task', 'project', 'user', 'system', 'feature', 'bug', 'issue', 'requirement']);
        const commonVerbs = new Set(['create', 'add', 'update', 'delete', 'implement', 'fix', 'build', 'develop']);
        const commonAdjectives = new Set(['urgent', 'high', 'low', 'critical', 'important', 'new', 'old', 'complex', 'simple']);
        return words.map(word => {
            const lower = word.toLowerCase();
            let tag = 'NN'; // Default to noun
            let description = 'Noun';
            if (commonVerbs.has(lower)) {
                tag = 'VB';
                description = 'Verb';
            }
            else if (commonAdjectives.has(lower)) {
                tag = 'JJ';
                description = 'Adjective';
            }
            else if (/^\d+$/.test(word)) {
                tag = 'CD';
                description = 'Cardinal number';
            }
            return { word, tag, description };
        });
    }
    /**
     * Analyze syntactic structure of the text
     */
    async analyzeSyntacticStructure(text, sentences) {
        try {
            const prompt = `Analyze the syntactic structure of this text. Identify:
1. Main clauses
2. Subordinate clauses
3. Noun phrases
4. Verb phrases
5. Prepositional phrases

Text: "${text}"

Return a JSON object with arrays for: mainClauses, subordinateClauses, and phrases (with noun, verb, prepositional arrays).`;
            const result = await this.openAIService.complete([{ role: 'user', content: prompt }], { maxTokens: 600, temperature: 0.3 });
            try {
                const parsed = JSON.parse(result.content.trim());
                return {
                    sentences,
                    mainClauses: parsed.mainClauses || [],
                    subordinateClauses: parsed.subordinateClauses || [],
                    phrases: {
                        noun: parsed.phrases?.noun || [],
                        verb: parsed.phrases?.verb || [],
                        prepositional: parsed.phrases?.prepositional || [],
                    },
                };
            }
            catch {
                return this.basicSyntacticAnalysis(text, sentences);
            }
        }
        catch (error) {
            console.error('Syntactic analysis with OpenAI failed:', error);
            return this.basicSyntacticAnalysis(text, sentences);
        }
    }
    /**
     * Basic syntactic analysis fallback
     */
    basicSyntacticAnalysis(text, sentences) {
        const mainClauses = sentences
            .filter(s => s.type === 'declarative' || s.type === 'imperative')
            .map(s => s.text);
        const subordinateClauses = sentences
            .filter(s => s.text.includes('if ') || s.text.includes('when ') || s.text.includes('because '))
            .map(s => s.text);
        // Extract basic phrases
        const nounPhrases = text.match(/(?:the |a |an )?(?:\w+ )*\w+(?= (?:is|are|was|were|will|would|should|could|can|may|might))/gi) || [];
        const verbPhrases = text.match(/(?:is|are|was|were|will|would|should|could|can|may|might) \w+(?: \w+)*/gi) || [];
        const prepPhrases = text.match(/(?:in|on|at|to|for|with|by|from|of|about) (?:the |a |an )?\w+(?: \w+)*/gi) || [];
        return {
            sentences,
            mainClauses,
            subordinateClauses,
            phrases: {
                noun: Array.from(new Set(nounPhrases)),
                verb: Array.from(new Set(verbPhrases)),
                prepositional: Array.from(new Set(prepPhrases)),
            },
        };
    }
    /**
     * Preserve context across multiple sentences
     */
    preserveContext(sentences) {
        // Track pronouns and their potential antecedents
        const pronouns = ['it', 'they', 'them', 'this', 'that', 'these', 'those', 'he', 'she'];
        let lastNoun;
        let lastSubject;
        return sentences.map((sentence, index) => {
            // Extract potential subject from current sentence
            const nounTokens = sentence.tokens.filter(t => t.type === 'word' && !pronouns.includes(t.text.toLowerCase()));
            if (nounTokens.length > 0) {
                lastNoun = nounTokens[0].text;
                sentence.subject = lastNoun;
            }
            else if (lastNoun) {
                // Use context from previous sentence
                sentence.subject = lastSubject;
            }
            // Simple verb extraction
            const verbCandidates = ['create', 'add', 'update', 'delete', 'implement', 'build', 'fix', 'need', 'require', 'should', 'must', 'will'];
            const verb = sentence.tokens.find(t => verbCandidates.includes(t.text.toLowerCase()));
            if (verb) {
                sentence.verb = verb.text;
            }
            // Extract potential object (simplified)
            const verbIndex = sentence.tokens.findIndex(t => t === verb);
            if (verbIndex > -1 && verbIndex < sentence.tokens.length - 1) {
                const objectTokens = sentence.tokens.slice(verbIndex + 1).filter(t => t.type === 'word');
                if (objectTokens.length > 0) {
                    sentence.object = objectTokens.map(t => t.text).join(' ');
                }
            }
            lastSubject = sentence.subject;
            return sentence;
        });
    }
    /**
     * Estimate token count for OpenAI
     */
    estimateTokens(text) {
        // Rough estimation: 1 token ≈ 4 characters
        return Math.ceil(text.length / 4);
    }
};
exports.TextParserService = TextParserService;
exports.TextParserService = TextParserService = __decorate([
    (0, tsyringe_1.injectable)(),
    __metadata("design:paramtypes", [openai_service_1.OpenAIService,
        langchain_service_1.LangChainService])
], TextParserService);
//# sourceMappingURL=text-parser.service.js.map