'use strict';

const nlp = require("../wordServices/nlp");
const beforeAnalysis = require("../../accounting/js/beforeAnalysis");
const TextAnalysisCommon = require("./textAnalysisCommon");
const AccountingServices = require("../../accounting/js/accountingServices");
const corpusServices = require("../command/corpusServices");

const nlpServices = require("./nlpServices");
const _ = require("lodash")
var fs = require('fs');
//
let MSKey = '79d213d131e74267b2d1fc197023d9fc';
let https = require('https');
let utils = require('../../helpers/utils');

module.exports = class TextAnalysisServices {
    constructor() {
    }
    // static GetRuleDictionaries(env, language)
    // {
    //     try {
    //         var rootFolder = "./sentenceAnalysis/" + language + "/";
    //         //var localRootFolder = "../" + language + "/";
    //         if (env == "production") {
    //             rootFolder += "generated/";
    //             //localRootFolder += "generated/";
    //         }
    //         var dictionaries = [];
    //         var folder = rootFolder + "dictionaries/";
    //         fs.readdirSync(folder).forEach(file => {
    //             if (file.length > 4 && file.endsWith(".csv")) {
    //                 var name = file.substring(0, file.length - 4);
    //                 dictionaries.push(name);
    //             }
    //         });
    //         return dictionaries;
    //     }
    //     catch(e){
    //         return [];
    //     }
    // }
    static GetRuleDictionaries(env, language, ruleType) {
        try {
            var dictionaries = require(TextAnalysisCommon.GetPrefix(language) + "/dictionaries.json");
            return dictionaries;
            // var rootFolder = "./sentenceAnalysis/" + language + "/";
            // //var localRootFolder = "../" + language + "/";
            // if (env == "production") {
            //     rootFolder += "generated/";
            //     //localRootFolder += "generated/";
            // }
            // var dictionaries = [];
            // var folder = rootFolder + "dictionaries/";
            // fs.readdirSync(folder).forEach(file => {
            //     if (file.length > 4 && file.endsWith(".csv")) {
            //         var name = file.substring(0, file.length - 4);
            //         dictionaries.push(name);
            //     }
            // });
            // return dictionaries;
        }
        catch (e) {
            return {};
        }
    }
    static GetRuleDictionaryColumnValues(env, language, dictionaryName, columnName) {
        var columns = [];
        var fileName = "./sentenceAnalysis/" + language + "/dictionaries/" + dictionaryName + ".csv";
        var stream = fs.readFileSync(fileName).toString();
        if (stream) {
            var lines = stream.split(/(?:\r\n?|\n)/);
            if (lines.length > 1) {
                var firstColumns = lines[0].split(",");
                var colIndice = -1;
                for (var ci = 0; ci < firstColumns.length; ci++) {
                    if (firstColumns[ci] == columnName) {
                        colIndice = ci;
                        break;
                    }
                }
                if (colIndice != -1) {
                    for (var ri = 1; ri < lines.length; ri++) {
                        var values = lines[ri].split(",");
                        if (colIndice < values.length &&
                            columns.indexOf(values[colIndice]) == -1) {
                            columns.push(values[colIndice]);
                        }
                    }
                }

            }
        }
        return columns;
    }
    static GetPhrases(env, language) {
        try {
            var phrases = require(TextAnalysisCommon.GetPrefix(language) + "/phraseRules.json");
            return phrases;
        }
        catch (e) {
            return {};
        }
    }
    static GetRuleMacros(env, language) {
        try {
            var result = [];
            var rootFolder = "./sentenceAnalysis/" + language + "/";
            var localRootFolder = TextAnalysisCommon.GetPrefix(language) + "/";
            if (env == "production") {
                rootFolder += "generated/";
                localRootFolder += "generated/";
            }
            var folder = rootFolder + "macros/";
            var localFolder = localRootFolder + "macros/";
            fs.readdirSync(folder).forEach(file => {
                if (file.length > 5 && file.endsWith(".json")) {
                    var name = file.substring(0, file.length - 5);

                    var localRuleFileName = localFolder + name;
                    var macros = require(localRuleFileName);

                    for (var mi = 0; mi < macros.length; mi++) {
                        var macro = macros[mi];
                        if (!macro.name) {
                            debugger;
                            continue;
                        }

                        var comment = macro.__comment__;
                        if (!comment) {
                            comment = name;
                        }
                        var description = "";;
                        if (macro.__description__) {
                            description = macro.__description__;
                        }
                        result.push({
                            name: macro.name,
                            comment: comment,
                            description: description
                        });
                    }
                }
            });
            return result;
        }
        catch (e) {
            return [];
        }
    }
    static GetRuleCategories(env, language, ruleType) {
        try {
            var localRootFolder = TextAnalysisCommon.GetPrefix(language) + "/";
            if (env == "production") {
                localRootFolder += "generated/";
            }
            var rules = require(localRootFolder + ruleType);
            var categories = [];
            for (var key in rules) {
                var category = rules[key].category;
                if (category && categories.indexOf(category) == -1) {
                    categories.push(category);
                }
            }
            return categories;
        }
        catch (e) {
            return [];
        }
    }
    static GetRules(env, language, ruleType, category) {
        try {
            var localRootFolder = TextAnalysisCommon.GetPrefix(language) + "/";
            if (env == "production") {
                localRootFolder += "generated/";
            }
            localRootFolder += ruleType;

            var rules = require(localRootFolder);
            var result = [];
            var jsons = {};
            localRootFolder += "/";
            for (var key in rules) {
                var rule = rules[key];
                if (rule.category == category) {
                    var json = jsons[rule.file];
                    if (!json) {
                        try {
                            json = require(localRootFolder + rule.file);
                            jsons[rule.file] = json;
                        }
                        catch (e) {
                            debugger;
                            console.error("rule file= " + rule.file);
                        }
                    }
                    var fileRules = json[ruleType];
                    for (var i = 0; i < fileRules.length; i++) {
                        if (fileRules[i].id == key) {
                            result.push(fileRules[i]);
                            break;
                        }
                    }
                }
            }
            return result;
        }
        catch (e) {
            return [];
        }
    }
    static GetTextNLP(language, text, convertSentence, addNLP) {
        return new Promise((resolve, reject) => {
            nlp.GetTextNLP(language, text, false)
                .then(nlpResult => {
                    if (!convertSentence) {
                        resolve(nlpResult);
                    }
                    else {
                        var sentenceAnalysisResults = [];
                        for (var si = 0; si < nlpResult.sentences.length; si++) {
                            var nlpSentence = nlpResult.sentences[si];
                            var sentenceAnalysisResult = {
                                sentence: nlpServices.ConvertSentence(nlpResult, si)
                            };
                            sentenceAnalysisResults.push(sentenceAnalysisResult);
                        }
                        if (!addNLP) {
                            resolve(sentenceAnalysisResults);
                        }
                        else {
                            var analysedText = {
                                sentenceNLP: nlpResult,
                                sentenceAnalysisResults: sentenceAnalysisResults
                            };
                            resolve(analysedText);
                        }
                    }
                }).catch(function (error) {
                    console.log(error.message);
                    debugger;
                    reject(error);
                });
        });
    }
    static AddCorrectionSuggestions(originalText, nlpSentence, results) {
        if (!results) {
            return;
        }
        var modifTokenServices = corpusServices.GetModificationTokenServices("errors", nlpSentence, results);
        var json = modifTokenServices.GetAllCorrectionSuggestions(originalText);

        var suggestions = [];
        for (var i = 0; i < json.corrections.length; i++) {
            var correction = json.corrections[i];
            suggestions.push(correction.sentence);
        }
        return suggestions;
    }
    static AddErrorSuggestions(originalText, nlpSentence, results) {
        if (!results) {
            return;
        }
        var modifTokenServices = corpusServices.GetModificationTokenServices("lessons", nlpSentence, results);
        var json = modifTokenServices.GetAllErrorSuggestions(originalText);

        var suggestions = [];
        for (var i = 0; i < json.errors.length; i++) {
            var error = json.errors[i];
            suggestions.push(error.sentence);
        }
        return suggestions;
    }
    static _AnalyseText(env, language, nlpResult, ruleType, category, jsonRules, addSuggestions, addNLP, resolve) {

        var srm = TextAnalysisCommon.GetTextAnalysisManager(env, language, ruleType, category, jsonRules);
        var sentenceAnalysisResults = [];
        var dupNLP = null;
        if (addNLP) {
            dupNLP = _.cloneDeep(nlpResult);
        }
        for (var si = 0; si < nlpResult.sentences.length; si++) {
            var nlpSentence = nlpResult.sentences[si];
            // console.log("AnalyseText nlpSentence.tokens.length= "+nlpSentence.tokens.length);
            // for (var ti=0; ti<nlpSentence.tokens.length; ti++)
            // {
            //     var token = nlpSentence.tokens[ti];
            //     if (!token)
            //     {
            //         debugger;
            //     }
            // }
            var sentenceAnalysisResult = {
                sentence: nlpServices.ConvertSentence(nlpResult, si)
            };
            var options = {
                sentence: "",
                generateConflictRules: false
            };
            var ruleTypeFound = false;
            if (ruleType == "lessonRules") {
                var results = [];
                srm.IdentifyLearningCards(nlpSentence, results, options);
                sentenceAnalysisResult.lessons = results;
                if (addSuggestions) {
                    sentenceAnalysisResult.errorSuggestions = TextAnalysisServices.AddErrorSuggestions("", nlpSentence, results);
                }
                ruleTypeFound = true;
            }
            else if (ruleType == "errorRules") {
                var results = [];
                srm.CheckErrors(nlpSentence, results, options);
                sentenceAnalysisResult.errors = results;
                if (addSuggestions) {
                    sentenceAnalysisResult.correctionSuggestions = TextAnalysisServices.AddCorrectionSuggestions("", nlpSentence, results);
                }
                ruleTypeFound = true;
            }
            else if (ruleType == "allRules") {
                var lessonResults = [];
                var errorResults = [];

                srm.Analyze(nlpSentence, lessonResults, errorResults, options);
                sentenceAnalysisResult.lessons = lessonResults;
                sentenceAnalysisResult.errors = errorResults;
                if (addSuggestions) {
                    sentenceAnalysisResult.errorSuggestions = TextAnalysisServices.AddErrorSuggestions("", nlpSentence, lessonResults);
                    sentenceAnalysisResult.correctionSuggestions = TextAnalysisServices.AddCorrectionSuggestions("", nlpSentence, errorResults);
                }
                ruleTypeFound = true;
            }
            else if (ruleType == "phraseRules") {
                srm.AnalyzePhrases(nlpSentence);
                sentenceAnalysisResult.nlpSentence = nlpSentence;
                ruleTypeFound = true;
            }
            else if (ruleType == "annotatorRules") {
                srm.AnalyzeAnnotators(nlpSentence);
                sentenceAnalysisResult.nlpSentence = nlpSentence;
                ruleTypeFound = true;
            }
            if (ruleTypeFound) {
                console.log("AnalyseText sentenceIndice= " + si + " tokens length = " + sentenceAnalysisResult.sentence.tokens.length);
                if (sentenceAnalysisResult.nlpSentence) {

                    for (var ti = 0; ti < nlpSentence.tokens.length; ti++) {
                        var token = nlpSentence.tokens[ti];
                        if (token.conditionResults) {
                            delete token.conditionResults;
                        }
                    }
                }
                sentenceAnalysisResults.push(sentenceAnalysisResult);
            }
            else {
                console.error("Wrong ruleType: " + ruleType);
                debugger;
            }
        }
        if (!addNLP) {
            resolve(sentenceAnalysisResults);
        }
        else {
            var analysedText = {
                sentenceNLP: dupNLP,
                sentenceAnalysisResults: sentenceAnalysisResults
            };
            resolve(analysedText);
        }
    }
    static AnalyseText(env, language, text, ruleType, category, jsonRules, addSuggestions, addNLP) {
        var self = this;
        return new Promise(function (resolve, reject) {

            console.log("AnalyseText text= " + text);
            if (jsonRules) {
                console.log("AnalyseText json ok= ");
            }
            if (language == "en" || language == "fr") {
                if (ruleType == "global") {
                    TextAnalysisServices.GlobalAnalyseText(env, language, text, addSuggestions, addNLP).then(function (results) {
                        resolve(results);
                    }).catch(function (error) {
                        console.error(error.message);
                        debugger;
                        reject(error);
                    });
                }
                else {

                    TextAnalysisServices.GetTextNLP(language, text)
                        .then(function (nlpResult) {
                            self._AnalyseText(env, language, nlpResult, ruleType, category, jsonRules, addSuggestions, addNLP, resolve);
                            // res.status(HttpStatus.OK).json(sentenceAnalysisResults);
                        }).catch(function (error) {
                            console.error(error.message);
                            debugger;
                            reject(error);
                        });
                }
            }
            else if (language == "billing" || language == "wording"|| language == "social"){
                var nlpResult = {
                    sentences: beforeAnalysis.getSentencesFromString(language, text)
                }

                if (ruleType == "global") {
                    var options = {
                        env: env,
                        language: language,
                        ruleType: "allRules",
                        category: category,
                        jsonRules: jsonRules
                    };
                    var result = AccountingServices.ExtractDataFromSentences(options, nlpResult.sentences);
                    resolve(result);
                }
                else {
                    self._AnalyseText(env, language, nlpResult, ruleType, category, jsonRules, addSuggestions, addNLP, resolve);
                }
            }
            else{
                reject(new Error("Wrong language= " + language));
            }
        });
    }
    static spellCheckMS(language, text) {
        var self = this;
        return new Promise((resolve, reject) => {
            if (!text) {
                debugger;
                reject();
                return;
            }
            console.log("spellCheckMS start");
            let host = 'api.cognitive.microsoft.com';
            let path = '/bing/v7.0/spellcheck';

            let mkt = "en-US";
            let mode = "proof";
            if (language == "fr") {
                mkt = "fr-FR";
                mode = "spell";
            }

            //let text = "Hollo, wrld!";
            if (!text.match(/[.?!:;)\]]$/)) {
                text += ".";
            }
            let query_string = "?mkt=" + mkt + "&mode=" + mode;

            let request_params = {
                method: 'POST',
                hostname: host,
                path: path + query_string,
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Content-Length': text.length + 5,
                    'Ocp-Apim-Subscription-Key': MSKey,
                    //        'X-Search-Location' : CLIENT_LOCATION,
                    //        'X-MSEdge-ClientID' : CLIENT_ID,
                    //        'X-MSEdge-ClientIP' : CLIENT_ID,
                }
            };

            let response_handler = function (response) {
                let body = '';
                response.on('data', function (d) {
                    body += d;
                });
                response.on('end', function () {
                    var result = JSON.parse(body);
                    resolve(result);
                    // var prevText = text;
                    // var correctedText = "";
                    // for (var i = result.flaggedTokens.length - 1; i >= 0; i--) {
                    //     var flaggedToken = result.flaggedTokens[i];

                    //     if (flaggedToken.offset > 0) {
                    //         correctedText = prevText.substring(0, flaggedToken.offset);
                    //     }
                    //     if (flaggedToken.suggestions) {
                    //         correctedText += flaggedToken.suggestions[0].suggestion;
                    //     }
                    //     else {
                    //         correctedText += flaggedToken.token;
                    //         debugger;
                    //     }
                    //     correctedText += prevText.substring(flaggedToken.offset + flaggedToken.token.length);
                    //     prevText = correctedText;
                    // }
                });
                response.on('error', function (e) {
                    debugger;
                    if (e && e.message) {
                        console.error('Error: ' + e.message);
                    }
                    reject(e);
                });
            };

            let req = https.request(request_params, response_handler);
            req.write("text=" + text);
            req.end();
        });
    }
    static GlobalAnalyseText(env, language, text, addSuggestions, addNLP) {
        var self = this;
        return new Promise((resolve, reject) => {
            TextAnalysisServices.spellCheckMS(language, text).then(function (spellCheckResult) {
                if (spellCheckResult && spellCheckResult.flaggedTokens && spellCheckResult.flaggedTokens.length) {

                    TextAnalysisServices.GetTextNLP(language, text).then(function (nlpResult) {

                        var sentenceAnalysisResults = [];
                        var dupNLP = null;
                        if (addNLP) {
                            dupNLP = _.cloneDeep(nlpResult);
                        }
                        for (var si = 0; si < nlpResult.sentences.length; si++) {
                            var nlpSentence = nlpResult.sentences[si];
                            var sentenceAnalysisResult = {
                                sentence: nlpServices.ConvertSentence(nlpResult, si)
                            };
                            sentenceAnalysisResults.push(sentenceAnalysisResult);
                        }
                        TextAnalysisServices.MoveFlaggedTokenInSentenceAnalysisResult(spellCheckResult.flaggedTokens, sentenceAnalysisResults);
                        if (addSuggestions) {
                            for (var si = 0; si < nlpResult.sentences.length; si++) {
                                var nlpSentence = nlpResult.sentences[si];
                                var sentenceAnalysisResult = sentenceAnalysisResults[si];
                                sentenceAnalysisResult.errorSuggestions = TextAnalysisServices.AddErrorSuggestions("", nlpSentence, sentenceAnalysisResult.lessons);
                                sentenceAnalysisResult.correctionSuggestions = TextAnalysisServices.AddCorrectionSuggestions("", nlpSentence, sentenceAnalysisResult.errors);

                            }
                        }
                        if (!addNLP) {
                            resolve(sentenceAnalysisResults);
                        }
                        else {
                            var analysedText = {
                                sentenceNLP: dupNLP,
                                sentenceAnalysisResults: sentenceAnalysisResults
                            };
                            resolve(analysedText);
                        }
                    }).catch(function (error) {
                        console.error(error.message);
                        resolve(null);
                        // reject(null);
                    });
                }
                else {
                    TextAnalysisServices.AnalyseText(env, language, text, "allRules", undefined, undefined, addSuggestions, addNLP).then(textAnalysisResult => {
                        // var textAnalysisResult = {
                        //     sentenceAnalysisResults: sentenceAnalysisResults
                        // };
                        resolve(textAnalysisResult);
                    }).catch(function (error) {
                        console.error(error.message);
                        reject(null);
                    });
                }
            }).catch(function (error) {
                reject(null);
                console.error(error.message);
            });
        });
    }
    static MoveFlaggedTokenInSentenceAnalysisResult(flaggedTokens, sentenceAnalysisResults) {
        if (flaggedTokens) {
            var keyTokens = {};
    
            for (var si = 0; si < sentenceAnalysisResults.length; si++) {
                var sentence = sentenceAnalysisResults[si].sentence;
    
                for (var ti = 0; ti < sentence.tokens.length; ti++) {
                    var token = sentence.tokens[ti];
                    var length = token.word.length;
                    var begin = token.begin;
                    var key = begin + "-" + length;
                    keyTokens[key] = {
                        sentenceIndice: si,
                        tokenIndices: [ti]
                    };
                    var prevEnd = token.end;
                    for (var ti1 = ti + 1; ti1 < sentence.tokens.length; ti1++) {
                        token = sentence.tokens[ti1];
                        length += token.begin - prevEnd;
                        // if (token.begin - prevEnd == 0)
                        // {
                        length += token.word.length;
                        key = begin + "-" + length;
                        keyTokens[key] = {
                            sentenceIndice: si,
                            tokenIndices: []
                        };
                        for (var ti2 = ti; ti2 <= ti1; ti2++) {
                            keyTokens[key].tokenIndices.push(ti2);
                        }
                        prevEnd = token.end;
                    }
                }
            }
            for (var i = 0; i < flaggedTokens.length; i++) {
                var flaggedToken = flaggedTokens[i];
                // console.log("MoveFlaggedTokenInSentenceAnalysisResult token= " + flaggedToken.token);
                var key = flaggedToken.offset + "-" + flaggedToken.token.length;
                var token = keyTokens[key];
                if (token) {
                    var sentenceAnalysisResult = sentenceAnalysisResults[token.sentenceIndice];
                    if (!sentenceAnalysisResult.errors) {
                        sentenceAnalysisResult.errors = [];
                    }
                    var error = {
                        tokenIndices: token.tokenIndices,
                        source: "MS_SpellCheck",
                        type: flaggedToken.type,
                        corrections: {
                            suggestions: []
                        }
                    };
                    if (flaggedToken.type == "UnknownToken") {
                        error.learningCard = {
                            type: utils.learningCard.types.correctionWord
                        };
                    }
                    // console.log("flaggedToken.suggestions.length = " + flaggedToken.suggestions.length);
                    for (var sugi = 0; sugi < flaggedToken.suggestions.length; sugi++) {
                        var suggestion = {
                            corrections: []
                        };
                        var correction = {};
                        if (flaggedToken.type == "UnknownToken") {
                            correction = {
                                type: "replaceAttValue",
                                att: "word",
                                text: flaggedToken.suggestions[sugi].suggestion
                            };
                        }
                        else if (flaggedToken.type == "RepeatedToken") {
                            correction.type = "delete";
                        }
                        else {
                            console.error(" flaggedToken.type not managed");
                            continue;
                        }
                        if (token.tokenIndices.length == 1) {
                            correction.tokenIndice = token.tokenIndices[0];
                        }
                        else {
                            correction.tokenIndices = token.tokenIndices;
                        }
                        suggestion.corrections.push(correction);
                        error.corrections.suggestions.push(suggestion);
                    }
                    sentenceAnalysisResult.errors.push(error);
                }
                else {
                    console.error("token not found key" + key);
                    debugger;
                }
            }
        }
    }
}
