define(
    [
        'jquery',
        'ko',
        'mage/translate',
        'Webkul_AdvanceSeoManager/js/model/stopWords',
    ],
    function ($, ko, $t, stopWordsList) {
        $.widget(
            'webkul.productrules',
            {
                errorMessages:[],
                successMessages:[],
                improvementMessages:[],
                options: {
                    seoRules: {
                        metaTitleLength: 60,
                        metaTitleLengthMin:50,
                        metaDescriptionLength: 156,
                        metaDescriptionLengthMin: 100,
                        productDescriptionLength: 300,
                        productDescriptionLengthMin: 100,
                        longTailedKeywordsLength: 3,
                        metaKeywordsLength: 20,
                        h1TagsCount: 1,
                        focusKeyWordDensity: 2.5,
                        focusKeyWordDensityMinimum: .5,
                        metaKeywordMinCount: 5,
                        minimumImages: 3,
                        errorMessages: {
                            metaTitleLengthShort: $t("meta title length is too short, add some more words"),
                            metaTitleNotDefined: $t("no meta title defined"),
                            metaDescriptionNotDefined: $t("no meta description defined"),
                            metaDescriptionLengthShort: $t("meta description length too short, add some more words"),
                            productDescriptionLengthSmall: $t("product description is less than 100 words, please add atleast 300 words"),
                            productDescriptionNotDefined: $t("no product description added, please add atleast 300 words"),
                            keywordsDensity: $t("keywords density is too low , it must be above "),
                            keywordsNotDefined: $t("no keywords defined add atleast 5 keywords"),
                            productDescriptionNoH1Tags: $t("no h1 tags found in the description"),
                            focusKeywordHighDensity: $t("keyword density is too high in product description"),
                            focusKeywordDensityNotFound: $t("no focus keywords found in product description"),
                            productImagesNotFound: $t("no product images added"),
                            productImagesAltNotFound: $t("no alt attribute defined for images"),
                            productRichSnippetsNotFound: $t("no rich snippets enabled for the product product"),
                            focusKeywordNotDefined: $t("no focus keyword defined"),
                            focusKeywordLowDensity: $t("keyword density is too low in product description"),
                            focusKeywordNotFoundInProductDescription: $t("focus keyword not found in product description"),
                            contentReadibility: $t('content readability is very poor, checked on the basis of <a href="https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests">Flesch reading ease</a>'),
                            focustKeywordNotFoundInMetaKeyword: $t("focus keyword can only be one of the meta keywords")
                        },
                        successMessages: {
                            metaTitleLengthGood: $t("meta title length is good"),
                            metaDescriptionLengthGood: $t("meta description length is good"),
                            productDescriptionLengthGood: $t("product description length is good"),
                            keywordsDensity: $t("keywords density is good"),
                            keywordsCountGood: $t("you have defined more than 5 keywords"),
                            focusKeywordDefined: $t("focus keyword defined"),
                            productImagesAdded: $t("good more than 3 product images added"),
                            focusKeywordGoodDensity: $t("focus keyword density is good"),
                            productImagesAltGood: $t("all the images has alt attribute defined"),
                            contentReadibility: $t('content readability is great'),
                            richSnippet: $t('excellent you have rich snippets enabled'),
                            focustKeywordFoundInMetaKeyword: $t("good your focus keyword is one of the meta keyword")
                        }, 
                        improvementMessages: {
                            metaDescriptionLengthSmall: $t("meta description length is too small, add some more words"),
                            productDescriptionLengthSmall: $t("product description is less than 300 words, consider adding more words"),
                            keywordsDensity: $t("add focus keyword in the title"),
                            keywordsCountSmall: $t("add atleast 5 meta keywords"),
                            metaDescriptionLengthLong: $t("meta description length is too wide, will get reduced on SERP, check snippet preview"),
                            metaTitleLengthLong: $t("meta title length is much wider, will get reduced on SERP check snippet preview"),
                            productImagesLessDefined: $t("add atleast three product images"),
                            focusKeywordLowDensity: $t("keyword density is too low in product description"),
                            focusKeywordNotFoundInMetaTitle: $t("focus keyword not found in meta title"),
                            productImagesInDescriptionNotFound: $t("consider adding images for better readability of the content"),
                            focusKeywordStopWords: $t("stop words found in focus keyword, consider removing them"),
                            productImagesAltCountLow: $t("consider adding alt attribute on all the images"),
                            contentReadibility: $t('content readability is good, but can be improved'),
                            richSnippet: $t('enable rich snippet for better, search result and conversion')
                        }
                    }
                },

                helper: {
                    /**
                     * check if content has any images
                     */
                    checkIfContentHasImages: function ($content, self) {
                        var img = $($content).find("img");
                        return img.length;
                    },

                    /**
                     * check if content has any images
                     */
                    checkIfContentHasImagesWithAlt: function ($content, self) {
                        var img = $($content).find("img");
                        var count = img.length;
                        var altCount = 0;
                        $.each(
                            img,
                            function (key, value) {
                                if ($(value).attr('alt')) {
                                    altCount++;
                                }
                            }
                        );
                        if (altCount > 0 && altCount == count) {
                            return 0;
                        } else if (altCount < count) {
                            return -1;
                        } else {
                            return 1;
                        }
                    },

                    /**
                     * check if content has any focus keywords
                     */
                    checkFocusKeywordDensity: function ($content, $focusKeyword, self) {
                        $content = $content.replace(/(<([^>]+)>)/ig,"");
                        var wordArray = $content.split(' ');
                        var result = {
                            totalCount: 0,
                            frequency: 0,
                            percent:0
                        };
                        //console.log($focusKeyword);
                        if (wordArray.length > 0) {
                            $.each(
                                wordArray,
                                function (key, value) {
                                    result.totalCount++;
                                }
                            );
                            var rx = new RegExp($focusKeyword, 'gim');
                            var matches = $content.match(rx);
                            if (matches) {
                                result.frequency = matches.length;
                            }
                            result.percent = (result.frequency/result.totalCount)*100;
                        }
                        //console.log(result);
                        return result;
                    },

                    /**
                     * check meta keywords count
                     */
                    metaKeyWordsCount: function (keywords, self) {
                        var words = keywords.split(',');
                        // console.log(words.length);
                        return words.length;
                    },

                    /**
                     * check meta title length
                     */
                    checkMetaTitleLength: function (title, self) {
                        
                        var titleLength = title.length;
                        if (titleLength > self.options.seoRules.metaTitleLength) {
                            // 1 represents length is greater then suggested length
                            return 1;
                        } else if (titleLength < self.options.seoRules.metaTitleLength && titleLength < self.options.seoRules.metaTitleLengthMin) {
                            // -1 represents length is less then suggested length
                            return -1;
                        } else if (titleLength < self.options.seoRules.metaTitleLength && titleLength >= self.options.seoRules.metaTitleLengthMin) {
                            // 0 represents length is perfect
                            return 0;
                        } else {
                            return 0;
                        }
                    },

                    /**
                     * check meta description length
                     */
                    checkMetaDescriptionLength: function (description, self) {
                        var descriptionLength = description.length;
                        if (descriptionLength > self.options.seoRules.metaDescriptionLength) {
                            return 1;
                        } else if (descriptionLength < self.options.seoRules.metaDescriptionLength && descriptionLength < self.options.seoRules.metaDescriptionLengthMin) {
                            return -1;
                        } else if (descriptionLength < self.options.seoRules.metaDescriptionLength && descriptionLength >= self.options.seoRules.metaDescriptionLengthMin) {
                            return 0;
                        } else {
                            return 0;
                        }
                    },

                    /**
                     * check content length
                     */
                    checkProductDescriptionLength: function (content, self) {
                        content = content.replace(/(<([^>]+)>)/ig,"");
                        var words = content.split(" ");
                        return words.length;
                    },

                    /**
                     * readability test
                     */
                    checkProductDescriptionReadability: function (content, self) {
                        return this.fleschReadingEaseTest(content);
                    },

                    /**
                     * reading ease test
                     */
                    fleschReadingEaseTest: function (content) {
                        var self = this;
                        
                        // remove html tags
                        var stripedContent = content.replace(/(<([^>]+)>)/ig,"");
                        stripedContent = stripedContent.toLowerCase();
                        var words = stripedContent.split(" ");
                        var sentences = stripedContent.split(". ");
                        var syllableCount = 0;
                        $.each(
                            words,
                            function (key, value) {
                                if (value.length > 1) {
                                    syllableCount += self.findSyllablesInWord(value);
                                }
                            }
                        );
                        // console.log(syllableCount);
                        var grade = 206.835 - 1.015*(words.length/sentences.length) - 84.6*(syllableCount/words.length);
                        return grade;

                    },

                    /**
                     * find syllables in a single word
                     */
                    findSyllablesInWord: function (word) {
                        var self = this;
                        var singleChar = '';
                        var totalVowelsPositions = [];
                        var syllablesCount = 0;
                        // console.log(word);
                        for (var i=0; i < word.length; i++) {
                            singleChar = word.charAt(i);
                            if (self.ifCharIsVowel(singleChar)) {
                                totalVowelsPositions.push(i);
                            }
                        }
                        // console.log( totalVowelsPositions);
                        var totoalVowels = totalVowelsPositions.length;
                        if (totalVowelsPositions.length > 0) {
                            var isLastCharE = false;
                            for (var j=0; j < totalVowelsPositions.length; j++) {
                                if (totalVowelsPositions[j] == word.length-1 && word.charAt(totalVowelsPositions[j]) == 'e') {
                                    totoalVowels = totoalVowels-1;
                                }

                                if ((totalVowelsPositions[j] && totalVowelsPositions[j+1]) && totalVowelsPositions[j] == totalVowelsPositions[j+1]-1) {
                                    totoalVowels = totoalVowels-1;
                                }
                            }
                            return totoalVowels;
                        }
                        return 0;
                    },

                    /**
                     * check if character is vowel
                     */
                    ifCharIsVowel: function (singleChar) {
                        var vowels = ['a','e','i','o','u'];
                        var isVowel = false;
                        for (var j=0; j < vowels.length; j++) {
                            // console.log(vowels[j]+"=="+singleChar);
                            if (vowels[j] == singleChar) {
                                isVowel = true;
                                break;
                            }
                        }

                        return isVowel;
                    },

                    /**
                     * check if content has stop words
                     */
                    checkStopWords: function (content, self) {
                        var words = content.split(' ');
                        var isTrue = false;
                        for (var i = 0; i < stopWordsList.words.length; i++) {
                            var word = " "+stopWordsList.words[i]+" ";
                            var rx = new RegExp(word,'gi');
                            var matches = content.match(rx);

                            if (matches) {
                                isTrue = matches.length;
                            }
                            if (isTrue) {
                                break;
                            }
                        }
                        return isTrue;
                    },

                    /**
                     * set error messages
                     */
                    setErrorMessages: function (self) {
                        var viewModel = self.options.seoObject;
                        viewModel.seoIssues([]);
                        viewModel.seoIssues(self.errorMessages);
                    },

                    /**
                     * set success messages
                     */
                    setSuccessMessages: function (self) {
                        var viewModel = self.options.seoObject;
                        viewModel.seoSuccess([]);
                        viewModel.seoSuccess(self.successMessages);
                    },

                    /**
                     * set improvement messages
                     */
                    setImprovementMessages: function (self) {
                        var viewModel = self.options.seoObject;
                        viewModel.seoWarnings([]);
                        viewModel.seoWarnings(self.improvementMessages);
                        // console.log(viewModel.seoWarnings());
                    },

                    seoPercentage: function (self) {
                        var viewModel = self.options.seoObject;
                        var totalError = self.errorMessages.length;
                        var totalSuccess = self.successMessages.length;
                        var totalImprovement = self.improvementMessages.length;
                        var percent = parseInt((totalSuccess/14)*100);
                        viewModel.positionLeft(percent+"%");
                    }
                },
                /**
                 * start processing
                 */
                _create: function () {
                    var self = this;
                    self.validateRules();
                },

                /**
                 * validate seo rules and generate data
                 */
                validateRules: function () {
                    var self = this;
                    self.successMessages = [];
                    self.errorMessages = [];
                    self.improvementMessages = [];
                    self.checkSeoTitle();
                    self.checkSeoDescription();
                    self.checkSeoKeywords();
                    self.checkProductDescription();
                    self.checkFocusKeyword();
                    self.checkProductImages();
                    self.checkProductRichSnippets();

                    self.helper.setErrorMessages(self);
                    self.helper.setSuccessMessages(self);
                    self.helper.setImprovementMessages(self);
                    self.helper.seoPercentage(self);
                    
                },

                /**
                 * validate seo title
                 */
                checkSeoTitle: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();
                    if (metaTitle) {
                        var titleStatus = self.helper.checkMetaTitleLength(metaTitle, self);
                        if (titleStatus == 1) {
                            self.improvementMessages.push({message: seoRules.improvementMessages.metaTitleLengthLong});
                        } else if (titleStatus == -1) {
                            self.errorMessages.push({message: seoRules.errorMessages.metaTitleLengthShort});
                        } else if (titleStatus == 0) {
                            self.successMessages.push({message: seoRules.successMessages.metaTitleLengthGood});
                        }
                    } else {
                        self.errorMessages.push({message: seoRules.errorMessages.metaTitleNotDefined});
                    }
                },

                /**
                 * validate seo description
                 */
                checkSeoDescription: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();
                    if (productMetaDescription) {
                        var status = self.helper.checkMetaDescriptionLength(productMetaDescription, self);
                        if (status == 1) {
                            self.improvementMessages.push({message: seoRules.improvementMessages.metaDescriptionLengthLong});
                        } else if (status == -1) {
                            self.errorMessages.push({message: seoRules.errorMessages.metaDescriptionLengthShort});
                        } else if (status == 0) {
                            self.successMessages.push({message: seoRules.successMessages.metaDescriptionLengthGood});
                        }
                    } else {
                        self.errorMessages.push({message: seoRules.errorMessages.metaDescriptionNotDefined});
                    }
                },

                /**
                 * validate seo keywords
                 */
                checkSeoKeywords: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();
                    if (metaKeywords) {
                        var status = self.helper.metaKeyWordsCount(metaKeywords, self);
                        if (status >= 5) {
                            self.successMessages.push({message: seoRules.successMessages.keywordsCountGood});
                        } else {
                            self.improvementMessages.push({message: seoRules.improvementMessages.keywordsCountSmall});
                        }
                    } else {
                        self.errorMessages.push({message: seoRules.errorMessages.keywordsNotDefined});
                    }
                },

                /**
                 * validate product description
                 */
                checkProductDescription: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();
                    if (productDescription) {
                        var length = self.helper.checkProductDescriptionLength(productDescription, self);

                        // check if description length is good enough
                        if (length > seoRules.productDescriptionLength) {
                            self.successMessages.push({message: seoRules.successMessages.productDescriptionLengthGood});
                            
                            self.checkFocusKeywordInProductDescription();
                            self.checkImagesInProductDescription();
                        } else if (length > seoRules.productDescriptionLengthMin) {
                            self.improvementMessages.push({message: seoRules.improvementMessages.productDescriptionLengthSmall});
                            self.checkFocusKeywordInProductDescription();
                            self.checkImagesInProductDescription();
                        } else {
                            self.errorMessages.push({message: seoRules.errorMessages.productDescriptionLengthSmall});
                            self.checkFocusKeywordInProductDescription();
                            self.checkImagesInProductDescription();
                        }
                        var grade = self.helper.checkProductDescriptionReadability(productDescription, self);
                        if (grade > 60) {
                            self.successMessages.push({message:seoRules.successMessages.contentReadibility});
                        } else {
                            self.errorMessages.push({message:seoRules.errorMessages.contentReadibility});
                        }
                    } else {
                        self.errorMessages.push({message: seoRules.errorMessages.productDescriptionNotDefined});
                    }
                    
                },

                /**
                 * check images in product description
                 */
                checkImagesInProductDescription: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();

                    // check images in the content

                    var imagesLength = self.helper.checkIfContentHasImages(productDescription, self);
                    if (imagesLength == 0) {
                        self.improvementMessages.push({message: seoRules.improvementMessages.productImagesInDescriptionNotFound});
                    } else {
                        //check images alt count
                        var altStatus = self.helper.checkIfContentHasImagesWithAlt(productDescription, self);
                        if (altStatus == 1) {
                            self.errorMessages.push({message: seoRules.errorMessages.productImagesAltNotFound});
                        }

                        if (altStatus == -1) {
                            self.improvementMessages.push({message: seoRules.improvementMessages.productImagesAltCountLow});
                        }

                        if (altStatus == 0) {
                            self.successMessages.push({message: seoRules.successMessages.productImagesAltGood});
                        }
                    }
                },

                /**
                 * check images in product description
                 */
                checkFocusKeywordInProductDescription: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();
                    // check focus keyword density

                    if (focusKeyword) {
                        var density = self.helper.checkFocusKeywordDensity(productDescription, focusKeyword, self);
                        if (density.percent) {
                            if (density.percent > seoRules.focusKeyWordDensityMinimum && density.percent <= seoRules.focusKeyWordDensity) {
                                self.successMessages.push({message: seoRules.successMessages.focusKeywordGoodDensity});
                            } else if (density.percent > seoRules.focusKeyWordDensity) {
                                self.errorMessages.push({message: seoRules.errorMessages.focusKeywordHighDensity});
                            } else if (density.percent < seoRules.focusKeyWordDensityMinimum) {
                                self.errorMessages.push({message: seoRules.errorMessages.focusKeywordLowDensity});
                            }
                        } else {
                            self.errorMessages.push({message: seoRules.errorMessages.focusKeywordDensityNotFound});
                        }
                    }
                },

                /**
                 * validate product description
                 */
                checkFocusKeyword: function () {
                    var self = this;
                    var viewModel = self.options.seoObject;
                    var seoRules = self.options.seoRules;
                    var productDescription = viewModel.productDescription();
                    var metaTitle = viewModel.metaTitle();
                    var productMetaDescription = viewModel.metaDescription();
                    var metaKeywords = viewModel.metaKeywords();
                    var focusKeyword = viewModel.focusKeyword();
                    if (focusKeyword) {
                        var wordCount = focusKeyword.split(" ");
                        if (wordCount.length >= 3) {
                            self.successMessages.push({message: $t("good you have used long tail focus keyword")});
                        } else {
                            self.improvementMessages.push({message: $t("consider using long tail keywords, as it is preferred for product search")});
                        }
                        if (self.helper.checkStopWords(focusKeyword, self)) {
                            self.improvementMessages.push({message: seoRules.improvementMessages.focusKeywordStopWords});
                        }
                        self.successMessages.push({message: seoRules.successMessages.focusKeywordDefined});

                        if (metaTitle) {
                            var density = self.helper.checkFocusKeywordDensity(metaTitle, focusKeyword, self);
                            if (density.percent > 0) {
                                self.successMessages.push({message: $t("good you have focus keyword defined in meta title")});
                            } else {
                                self.improvementMessages.push({message: $t("no focus keyword found in meta title, try to add meta keyword at the starting")});
                            }
                        }

                        if (productMetaDescription) {
                            var density = self.helper.checkFocusKeywordDensity(productMetaDescription, focusKeyword, self);
                            if (density.percent > 0) {
                                self.successMessages.push({message: $t("good you have focus keyword defined in meta description")});
                            } else {
                                self.improvementMessages.push({message: $t("no focus keyword found in meta description")});
                            }
                        }
                        let isFound = false;
                        if (metaKeywords && metaKeywords.length > 0) {
                            let keywordsArr = metaKeywords.split(',');
                            
                            for (var i=0; i < keywordsArr.length; i++) {
                                console.log (keywordsArr[i].trim() +"==="+ focusKeyword.trim());
                                if (keywordsArr[i].trim() === focusKeyword.trim()) {
                                    isFound = true;
                                    break;
                                }
                            }
                        }
                        if (isFound) {
                            self.successMessages.push({message: seoRules.successMessages.focustKeywordFoundInMetaKeyword});
                        } else {
                            self.errorMessages.push({message: seoRules.errorMessages.focustKeywordNotFoundInMetaKeyword});
                        }
                    } else {
                        self.errorMessages.push({message: seoRules.errorMessages.focusKeywordNotDefined});
                    }
                    
                },

                /**
                 * check product images count
                 */
                checkProductImages: function () {
                    var self = this;
                    var count = 0;
                    if (window.seoConfiguration.product.productImagesCount > 0) {
                        count = window.seoConfiguration.product.productImagesCount;
                    }
                    if (count) {
                        if (count > 3) {
                            self.successMessages.push({message: $t("great you have uploaded")+count+$t("images")});
                        } else {
                            self.improvementMessages.push({message: $t("you have uploaded ") +count+ $t("product image(s), consider uploading more images")});
                        }
                    } else {
                        self.errorMessages.push({message: $t("no product images found, upload atleast 3 images")});
                    }
                },

                /**
                 * rich snippet check
                 */
                checkProductRichSnippets: function () {
                    var self = this;
                    var count = 0;
                    var seoRules = self.options.seoRules;
                    if (window.seoConfiguration.richSnippets) {
                        self.successMessages.push({message: seoRules.successMessages.richSnippet});
                    } else {
                        self.improvementMessages.push({message: seoRules.improvementMessages.richSnippet});
                    }
                },
            }
        );

        return $.webkul.productrules;
    }
);