using ladaexpress.vn.Infrastructures.DTO.Models.Seo;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Text.RegularExpressions;
using System.Text;
using System.Globalization;

namespace ladaexpress.vn.Infrastructures.Services
{
    /// <summary>
    /// Implementation của IContentOptimizationService
    /// </summary>
    public class ContentOptimizationService : IContentOptimizationService
    {
        private readonly IAppConfigService _appConfigService;
        private readonly IMemoryCache _memoryCache;
        private readonly IConfiguration _configuration;
        private readonly ILogger<ContentOptimizationService> _logger;
        private readonly string _cacheKeyPrefix = "ContentOpt_";

        // Common Vietnamese stop words
        private readonly HashSet<string> _vietnameseStopWords = new HashSet<string>
        {
            "và", "của", "có", "là", "được", "các", "cho", "trong", "với", "về", "từ", "để", "khi", "không", "này", "đã", "sẽ", "cũng", "như", "một", "những", "nhiều", "hay", "hoặc", "nhưng", "mà", "nếu", "thì", "vì", "do", "nên", "rồi", "đây", "đó", "tại", "theo", "sau", "trước", "giữa", "dưới", "trên", "ngoài", "trong", "bên", "cạnh"
        };

        public ContentOptimizationService(
            IAppConfigService appConfigService,
            IMemoryCache memoryCache,
            IConfiguration configuration,
            ILogger<ContentOptimizationService> logger)
        {
            _appConfigService = appConfigService;
            _memoryCache = memoryCache;
            _configuration = configuration;
            _logger = logger;
        }

        public async Task<string> GenerateOptimizedTitleAsync(string baseTitle, string contentType, string? keywords = null)
        {
            try
            {
                var cacheKey = $"{_cacheKeyPrefix}Title_{baseTitle?.GetHashCode()}_{contentType}";
                if (_memoryCache.TryGetValue(cacheKey, out string? cached) && !string.IsNullOrEmpty(cached))
                {
                    return cached;
                }

                // Get title templates from AppConfig
                var template = await GetConfigValueAsync($"SEO.{contentType}.TitleTemplate", "{title}");
                var maxLength = int.Parse(await GetConfigValueAsync("SEO.Title.MaxLength", "60"));
                var brandName = await GetConfigValueAsync("SEO.BrandName", "LADA Express");

                var optimizedTitle = template.Replace("{title}", baseTitle);

                // Add keywords if provided
                //if (!string.IsNullOrEmpty(keywords))
                //{
                //    var keywordTemplate = await GetConfigValueAsync($"SEO.{contentType}.TitleWithKeywords", "{title} - {keywords} | {brand}");
                //    optimizedTitle = keywordTemplate
                //        .Replace("{title}", baseTitle)
                //        .Replace("{keywords}", keywords)
                //        .Replace("{brand}", brandName);
                //}

                // Optimize length
                optimizedTitle = OptimizeLength(optimizedTitle, maxLength);

                // Cache for 1 hour
                _memoryCache.Set(cacheKey, optimizedTitle, TimeSpan.FromHours(1));
                return optimizedTitle;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error generating optimized title for: {BaseTitle}", baseTitle);
                return baseTitle; // Fallback to original title
            }
        }

        public async Task<string> GenerateOptimizedDescriptionAsync(string content, string contentType, int targetLength = 155)
        {
            try
            {
                var cacheKey = $"{_cacheKeyPrefix}Desc_{content?.GetHashCode()}_{contentType}";
                if (_memoryCache.TryGetValue(cacheKey, out string? cached) && !string.IsNullOrEmpty(cached))
                {
                    return cached;
                }

                // Clean HTML and extract text
                var cleanText = StripHtml(content);

                // Get description template
                var template = await GetConfigValueAsync($"SEO.{contentType}.DescriptionTemplate", "{content}");
                var maxLength = int.Parse(await GetConfigValueAsync("SEO.Description.MaxLength", targetLength.ToString()));

                var optimizedDescription = template.Replace("{content}", cleanText);

                // Optimize for readability and length
                optimizedDescription = OptimizeDescriptionReadability(optimizedDescription);
                optimizedDescription = OptimizeLength(optimizedDescription, maxLength);

                // Ensure it ends with proper punctuation
                if (!string.IsNullOrEmpty(optimizedDescription) && !optimizedDescription.EndsWith(".") && !optimizedDescription.EndsWith("!") && !optimizedDescription.EndsWith("?"))
                {
                    optimizedDescription += ".";
                }

                // Cache for 30 minutes
                _memoryCache.Set(cacheKey, optimizedDescription, TimeSpan.FromMinutes(30));
                return optimizedDescription;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error generating optimized description");
                return StripHtml(content).Substring(0, Math.Min(content.Length, targetLength));
            }
        }

        public async Task<List<string>> ExtractKeywordsAsync(string title, string content, int maxKeywords = 10)
        {
            try
            {
                var cacheKey = $"{_cacheKeyPrefix}Keywords_{title?.GetHashCode()}_{content?.GetHashCode()}";
                if (_memoryCache.TryGetValue(cacheKey, out List<string>? cached) && cached != null)
                {
                    return cached;
                }

                var keywords = new List<string>();

                // Clean and prepare text
                var fullText = $"{title} {StripHtml(content)}".ToLower();

                // Extract words and phrases
                var words = ExtractWordsAndPhrases(fullText);

                // Filter out stop words and short words
                var filteredWords = words
                    .Where(w => w.Length >= 3 && !_vietnameseStopWords.Contains(w))
                    .GroupBy(w => w)
                    .OrderByDescending(g => g.Count())
                    .Take(maxKeywords * 2) // Get more than needed for filtering
                    .Select(g => g.Key)
                    .ToList();

                // Add brand-related keywords
                var brandKeywords = await GetConfigValueAsync("SEO.BrandKeywords", "LADA Express, vận chuyển, giao hàng");
                keywords.AddRange(brandKeywords.Split(',').Select(k => k.Trim()));

                // Combine and deduplicate
                keywords.AddRange(filteredWords);
                keywords = keywords.Distinct().Take(maxKeywords).ToList();

                // Cache for 1 hour
                _memoryCache.Set(cacheKey, keywords, TimeSpan.FromHours(1));
                return keywords;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error extracting keywords");
                return new List<string>();
            }
        }

        public async Task<string> OptimizeContentAsync(string content, List<string>? targetKeywords = null)
        {
            try
            {
                if (string.IsNullOrEmpty(content)) return content;

                var optimizedContent = content;

                // Add heading structure if missing
                optimizedContent = EnsureHeadingStructure(optimizedContent);

                // Optimize images alt text
                optimizedContent = OptimizeImageAltTexts(optimizedContent, targetKeywords);

                // Add internal links where appropriate
                optimizedContent = await AddInternalLinks(optimizedContent);

                // Ensure proper paragraph structure
                optimizedContent = OptimizeParagraphStructure(optimizedContent);

                return optimizedContent;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error optimizing content");
                return content;
            }
        }

        public async Task<SeoQualityReport> AnalyzeSeoQualityAsync(string title, string description, string content, List<string>? keywords = null)
        {
            var report = new SeoQualityReport();
            var score = 100;

            try
            {
                // Title analysis
                if (string.IsNullOrEmpty(title))
                {
                    report.Weaknesses.Add("Thiếu tiêu đề");
                    score -= 20;
                }
                else
                {
                    if (title.Length > 60)
                    {
                        report.Weaknesses.Add($"Tiêu đề quá dài ({title.Length} ký tự), nên dưới 60");
                        score -= 10;
                    }
                    else if (title.Length < 30)
                    {
                        report.Suggestions.Add("Tiêu đề có thể dài hơn để tối ưu SEO");
                        score -= 5;
                    }
                    else
                    {
                        report.Strengths.Add("Độ dài tiêu đề tốt");
                    }
                }

                // Description analysis
                if (string.IsNullOrEmpty(description))
                {
                    report.Weaknesses.Add("Thiếu meta description");
                    score -= 15;
                }
                else
                {
                    if (description.Length > 160)
                    {
                        report.Weaknesses.Add($"Meta description quá dài ({description.Length} ký tự)");
                        score -= 8;
                    }
                    else if (description.Length < 120)
                    {
                        report.Suggestions.Add("Meta description có thể dài hơn");
                        score -= 3;
                    }
                    else
                    {
                        report.Strengths.Add("Độ dài meta description tốt");
                    }
                }

                // Content analysis
                var contentAnalysis = AnalyzeContentStructure(content);
                report.Strengths.AddRange(contentAnalysis.Strengths);
                report.Weaknesses.AddRange(contentAnalysis.Weaknesses);
                report.Suggestions.AddRange(contentAnalysis.Suggestions);
                score += contentAnalysis.ScoreAdjustment;

                // Keywords analysis
                if (keywords != null && keywords.Any())
                {
                    var keywordDensity = CalculateKeywordDensity(content, keywords);
                    report.Details["KeywordDensity"] = keywordDensity;

                    if (keywordDensity < 0.5)
                    {
                        report.Suggestions.Add("Có thể tăng mật độ từ khóa");
                        score -= 5;
                    }
                    else if (keywordDensity > 3.0)
                    {
                        report.Weaknesses.Add("Mật độ từ khóa quá cao, có thể bị coi là spam");
                        score -= 10;
                    }
                    else
                    {
                        report.Strengths.Add("Mật độ từ khóa hợp lý");
                    }
                }

                report.Score = Math.Max(0, Math.Min(100, score));
                return report;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error analyzing SEO quality");
                report.Weaknesses.Add("Lỗi phân tích chất lượng SEO");
                report.Score = 50; // Default moderate score on error
                return report;
            }
        }

        public async Task<string> GenerateImageAltTextAsync(string imageUrl, string context, List<string>? keywords = null)
        {
            try
            {
                var template = await GetConfigValueAsync("SEO.Image.AltTemplate", "{context} - LADA Express");
                var altText = template.Replace("{context}", context);

                // Add keywords if provided
                if (keywords != null && keywords.Any())
                {
                    var primaryKeyword = keywords.FirstOrDefault();
                    if (!string.IsNullOrEmpty(primaryKeyword) && !altText.Contains(primaryKeyword))
                    {
                        altText = $"{primaryKeyword} - {altText}";
                    }
                }

                // Optimize length (alt text should be under 125 characters)
                return OptimizeLength(altText, 125);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error generating image alt text");
                return context;
            }
        }

        public int CalculateReadingTime(string content, int wordsPerMinute = 200)
        {
            try
            {
                var cleanText = StripHtml(content);
                var wordCount = CountWords(cleanText);
                var readingTime = Math.Max(1, (int)Math.Ceiling((double)wordCount / wordsPerMinute));
                return readingTime;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error calculating reading time");
                return 1; // Default 1 minute
            }
        }

        public async Task<string> GenerateContentSummaryAsync(string content, int maxLength = 300)
        {
            try
            {
                var cleanText = StripHtml(content);
                if (cleanText.Length <= maxLength) return cleanText;

                // Try to find natural break points
                var sentences = cleanText.Split('.', StringSplitOptions.RemoveEmptyEntries);
                var summary = new StringBuilder();

                foreach (var sentence in sentences)
                {
                    var trimmedSentence = sentence.Trim();
                    if (summary.Length + trimmedSentence.Length + 2 <= maxLength)
                    {
                        summary.Append(trimmedSentence).Append(". ");
                    }
                    else
                    {
                        break;
                    }
                }

                return summary.ToString().Trim();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error generating content summary");
                return StripHtml(content).Substring(0, Math.Min(content.Length, maxLength));
            }
        }

        public List<string> ValidateContentStructure(string content)
        {
            var issues = new List<string>();

            try
            {
                // Check for heading structure
                if (!Regex.IsMatch(content, @"<h[1-6]", RegexOptions.IgnoreCase))
                {
                    issues.Add("Nội dung thiếu cấu trúc heading (H1, H2, H3...)");
                }

                // Check for images without alt text
                var imagesWithoutAlt = Regex.Matches(content, @"<img(?![^>]*alt=)", RegexOptions.IgnoreCase);
                if (imagesWithoutAlt.Count > 0)
                {
                    issues.Add($"Có {imagesWithoutAlt.Count} hình ảnh thiếu alt text");
                }

                // Check content length
                var wordCount = CountWords(StripHtml(content));
                if (wordCount < 300)
                {
                    issues.Add($"Nội dung quá ngắn ({wordCount} từ), nên có ít nhất 300 từ");
                }

                // Check for internal links
                var internalLinks = Regex.Matches(content, @"<a[^>]*href=[""'](?!http)", RegexOptions.IgnoreCase);
                if (internalLinks.Count == 0)
                {
                    issues.Add("Nội dung thiếu liên kết nội bộ");
                }

                return issues;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error validating content structure");
                issues.Add("Lỗi kiểm tra cấu trúc nội dung");
                return issues;
            }
        }

        #region Private Helper Methods

        private async Task<string> GetConfigValueAsync(string key, string defaultValue)
        {
            try
            {
                var value = await _appConfigService.GetConfigValueAsync(key, defaultValue);
                return string.IsNullOrEmpty(value) ? defaultValue : value;
            }
            catch
            {
                return defaultValue;
            }
        }

        private string OptimizeLength(string text, int maxLength)
        {
            if (string.IsNullOrEmpty(text) || text.Length <= maxLength)
                return text;

            var truncated = text.Substring(0, maxLength - 3);
            var lastSpace = truncated.LastIndexOf(' ');

            if (lastSpace > 0)
                truncated = truncated.Substring(0, lastSpace);

            return truncated + "...";
        }

        private string StripHtml(string html)
        {
            if (string.IsNullOrEmpty(html)) return "";
            return Regex.Replace(html, @"<[^>]+>", " ").Trim();
        }

        private List<string> ExtractWordsAndPhrases(string text)
        {
            var words = new List<string>();

            // Extract individual words
            var wordMatches = Regex.Matches(text, @"\b\w{3,}\b", RegexOptions.IgnoreCase);
            words.AddRange(wordMatches.Cast<Match>().Select(m => m.Value.ToLower()));

            // Extract 2-word phrases
            var phraseMatches = Regex.Matches(text, @"\b(\w+\s+\w+)\b", RegexOptions.IgnoreCase);
            words.AddRange(phraseMatches.Cast<Match>().Select(m => m.Value.ToLower()));

            return words;
        }

        private string OptimizeDescriptionReadability(string description)
        {
            // Remove extra spaces
            description = Regex.Replace(description, @"\s+", " ").Trim();

            // Ensure first letter is uppercase
            if (!string.IsNullOrEmpty(description))
            {
                description = char.ToUpper(description[0]) + description.Substring(1);
            }

            return description;
        }

        private string EnsureHeadingStructure(string content)
        {
            // Basic implementation - in a real scenario, this would be more sophisticated
            if (!Regex.IsMatch(content, @"<h[1-6]", RegexOptions.IgnoreCase))
            {
                // Try to identify paragraphs that could be headings
                content = Regex.Replace(content, @"<p><strong>([^<]+)</strong></p>", "<h3>$1</h3>", RegexOptions.IgnoreCase);
            }
            return content;
        }

        private string OptimizeImageAltTexts(string content, List<string>? keywords)
        {
            var keywordList = keywords ?? new List<string>();

            // Find images without alt text and add generic alt text
            content = Regex.Replace(content, @"<img([^>]*?)(?<!alt=[""'][^""']*?)(/?>)", match =>
            {
                var imgTag = match.Value;
                var altText = "Hình ảnh LADA Express";

                if (keywordList.Any())
                {
                    altText = $"{keywordList.First()} - {altText}";
                }

                return imgTag.Replace("/>", $" alt=\"{altText}\" />").Replace(">", $" alt=\"{altText}\">");
            });

            return content;
        }

        private async Task<string> AddInternalLinks(string content)
        {
            // Basic implementation - would be more sophisticated in practice
            var linkableTerms = await GetConfigValueAsync("SEO.InternalLinks.Terms", "dịch vụ,vận chuyển,giao hàng");
            var terms = linkableTerms.Split(',').Select(t => t.Trim()).ToList();

            foreach (var term in terms)
            {
                if (!string.IsNullOrEmpty(term))
                {
                    var pattern = $@"\b{Regex.Escape(term)}\b";
                    var replacement = $"<a href=\"/tim-kiem?q={Uri.EscapeDataString(term)}\">{term}</a>";
                    content = Regex.Replace(content, pattern, replacement, RegexOptions.IgnoreCase);
                }
            }

            return content;
        }

        private string OptimizeParagraphStructure(string content)
        {
            // Ensure paragraphs are not too long
            content = Regex.Replace(content, @"<p>(.{500,}?)</p>", match =>
            {
                var text = match.Groups[1].Value;
                var sentences = text.Split('.', StringSplitOptions.RemoveEmptyEntries);

                if (sentences.Length > 3)
                {
                    var midPoint = sentences.Length / 2;
                    var firstPart = string.Join(".", sentences.Take(midPoint)) + ".";
                    var secondPart = string.Join(".", sentences.Skip(midPoint)) + ".";
                    return $"<p>{firstPart}</p><p>{secondPart}</p>";
                }

                return match.Value;
            });

            return content;
        }

        private (List<string> Strengths, List<string> Weaknesses, List<string> Suggestions, int ScoreAdjustment) AnalyzeContentStructure(string content)
        {
            var strengths = new List<string>();
            var weaknesses = new List<string>();
            var suggestions = new List<string>();
            var scoreAdjustment = 0;

            var wordCount = CountWords(StripHtml(content));
            var headingCount = Regex.Matches(content, @"<h[1-6]", RegexOptions.IgnoreCase).Count;
            var imageCount = Regex.Matches(content, @"<img", RegexOptions.IgnoreCase).Count;
            var linkCount = Regex.Matches(content, @"<a[^>]*href", RegexOptions.IgnoreCase).Count;

            // Word count analysis
            if (wordCount >= 800)
            {
                strengths.Add($"Nội dung dài tốt ({wordCount} từ)");
                scoreAdjustment += 5;
            }
            else if (wordCount >= 300)
            {
                strengths.Add($"Độ dài nội dung chấp nhận được ({wordCount} từ)");
            }
            else
            {
                weaknesses.Add($"Nội dung quá ngắn ({wordCount} từ)");
                scoreAdjustment -= 10;
            }

            // Heading structure
            if (headingCount >= 3)
            {
                strengths.Add("Cấu trúc heading tốt");
                scoreAdjustment += 5;
            }
            else if (headingCount >= 1)
            {
                suggestions.Add("Có thể thêm nhiều heading hơn để cải thiện cấu trúc");
            }
            else
            {
                weaknesses.Add("Thiếu cấu trúc heading");
                scoreAdjustment -= 8;
            }

            // Image usage
            if (imageCount > 0)
            {
                strengths.Add("Có sử dụng hình ảnh");
                scoreAdjustment += 3;
            }
            else
            {
                suggestions.Add("Thêm hình ảnh để làm phong phú nội dung");
            }

            // Internal linking
            if (linkCount > 0)
            {
                strengths.Add("Có liên kết nội bộ");
                scoreAdjustment += 3;
            }
            else
            {
                suggestions.Add("Thêm liên kết nội bộ để cải thiện SEO");
            }

            return (strengths, weaknesses, suggestions, scoreAdjustment);
        }

        private double CalculateKeywordDensity(string content, List<string> keywords)
        {
            var cleanText = StripHtml(content).ToLower();
            var totalWords = CountWords(cleanText);

            if (totalWords == 0) return 0;

            var keywordOccurrences = keywords.Sum(keyword =>
                Regex.Matches(cleanText, $@"\b{Regex.Escape(keyword.ToLower())}\b").Count);

            return ((double)keywordOccurrences / totalWords) * 100;
        }

        private int CountWords(string text)
        {
            if (string.IsNullOrWhiteSpace(text)) return 0;
            return Regex.Matches(text, @"\b\w+\b").Count;
        }

        #endregion
    }
}