using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using NSoup;
using NSoup.Nodes;
using PowerEasy.WebFuture.DataMigrations.Foundation.Model;

namespace PowerEasy.WebFuture.DataMigrations.Foundation.Service
{
    /// <summary>
    /// HTML 格式化助手类。
    /// </summary>
    public static class HtmlFormatHelper
    {
        private static Regex replaceStyleRe1 = new Regex(@"style=(""|')[^=>]*(""|')([>])", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private static Regex replaceStyleRe2 = new Regex(@"style=(""|')[^=>]*(""|')([(\s+\w+=)])", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private static Regex textAlignRe = new Regex(@"text-align:\s{0,10}center", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        /// <summary>
        /// 处理 HTML 格式（清洗数据，去掉内容的样式）。
        /// </summary>
        /// <param name="html">HTML 文本。</param>
        /// <returns>处理后的 HTML 文本。</returns>
        public static string ProcessHtmlContent(string html)
        {
            var setting = new HtmlFormatSetting
            {
                FirstLineIndent = true,
                RemoveFontFamily = true,
                RemoveFontSize = true,
                RemoveFormat = true,
                RemoveImage = false,
                RemoveLink = false,
                RemoveEmptyLine = false,
                RemoveTitleFromContent = false,
                ImageCentered = true
            };

            var configs = new bool[]
            {
                setting.FirstLineIndent,
                setting.RemoveEmptyLine,
                setting.RemoveFontFamily,
                setting.RemoveFontSize,
                setting.RemoveFormat,
                setting.RemoveImage,
                setting.RemoveLink,
                setting.ImageCentered
            };

            if (!configs.Any(x => x))
            {
                return html;
            }

            var htmlDoc = NSoupClient.Parse(html);

            return ProcessHtmlContent(htmlDoc, setting);
        }

        /// <summary>
        /// 处理 HTML 格式。
        /// </summary>
        /// <param name="doc">NSoup 对象。</param>
        /// <param name="setting">HTML 格式设置。</param>
        /// <returns>处理后的 HTML 文本。</returns>
        private static string ProcessHtmlContent(Document doc, HtmlFormatSetting setting)
        {
            if (doc == null || doc.Children.Count < 1)
            {
                return doc == null ? null : doc.Html();
            }

            // 处理 HTML 格式。
            foreach (var item in doc.Children)
            {
                ProcessHtml(item, setting);
            }

            // 清除空白行
            if (setting.RemoveEmptyLine)
            {
                var emptyLines = doc.GetElementsByTag("p");
                foreach (var element in emptyLines)
                {
                    if (!element.HasText)
                    {
                        var hasContent = false;
                        var childs = new Stack<Element>(10);
                        foreach (var item in element.Children)
                        {
                            childs.Push(item);
                        }

                        while (childs.Count > 0)
                        {
                            var child = childs.Pop();

                            if (child.TagName() == "img")
                            {
                                hasContent = true;
                                break;
                            }

                            foreach (var item in child.Children)
                            {
                                childs.Push(item);
                            }
                        }

                        if (!hasContent)
                        {
                            element.Remove();
                        }
                    }
                }
            }

            return doc.Html();
        }

        private static void ProcessHtml(Element element, HtmlFormatSetting setting)
        {
            if (element == null)
            {
                return;
            }

            var tagName = element.TagName();

            // 图片处理
            if (tagName == "img")
            {
                // 清除图片。
                if (setting.RemoveImage)
                {
                    element.Remove();
                    return;
                }

                // 图片居中
                if (setting.ImageCentered)
                {
                    // 段落里面只有图片时，段落内容居中
                    var parentNode = element.Parent;
                    var loopCount = 5;
                    while (parentNode.TagName() != "p" && parentNode.Parent != null && loopCount-- > 0)
                    {
                        if (parentNode.Parent != null && parentNode.Parent.TagName() != "body")
                        {
                            parentNode = parentNode.Parent;
                        }
                    }

                    if (parentNode.TagName() == "p" && !parentNode.HasText)
                    {
                        parentNode.AddClass("center");
                    }
                    else
                    {
                        element.AddClass("center");
                    }
                }
            }

            var style = element.Attr("style");
            var styles = string.IsNullOrWhiteSpace(style) ? new List<string>() : style.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();

            // 清除格式
            if (setting.RemoveFormat && !string.IsNullOrWhiteSpace(style))
            {
                // 如果有居中的，则单独保留居中样式
                styles.RemoveAll(css => !textAlignRe.IsMatch(css));
            }

            // 移除字体大小和字体
            if (!setting.RemoveFormat && (setting.RemoveFontFamily || setting.RemoveFontSize))
            {
                if (!string.IsNullOrWhiteSpace(style))
                {
                    var removeStyleValues = new HashSet<string>();
                    for (int i = 0; i < styles.Count; i++)
                    {
                        if (setting.RemoveFontFamily && styles[i].Contains("font-family", StringComparison.OrdinalIgnoreCase))
                        {
                            removeStyleValues.Add(styles[i]);
                        }

                        if (setting.RemoveFontSize && styles[i].Contains("font-size", StringComparison.OrdinalIgnoreCase))
                        {
                            removeStyleValues.Add(styles[i]);
                        }
                    }

                    foreach (var item in removeStyleValues)
                    {
                        styles.Remove(item);
                    }
                }
            }

            var children = element.Children;
            if (tagName == "p")
            {
                // 首行缩进
                if (setting.FirstLineIndent)
                {
                    if (styles.Any(x => x.Contains("text-indent", StringComparison.OrdinalIgnoreCase)))
                    {
                        for (int i = 0; i < styles.Count; i++)
                        {
                            if (styles[i].Contains("text-indent", StringComparison.OrdinalIgnoreCase))
                            {
                                styles.Remove(styles[i]);
                                break;
                            }
                        }
                    }

                    // 如果有居中的，则保留居中样式
                    if (!textAlignRe.IsMatch(style))
                    {
                        // 如果里面有图片，则不使用缩进
                        var hasImage = element.Html().Contains("<img", StringComparison.InvariantCultureIgnoreCase);
                        if (!hasImage)
                        {
                            styles.Add("text-indent:2em");
                        }
                        else if (element.ChildNodes.Count > 0)
                        {
                            // 给图片后面的子元素加缩进
                            var images = element.GetElementsByTag("img");
                            foreach (var item in images)
                            {
                                item.After("&emsp;&emsp;");
                            }
                        }
                    }
                }
            }

            element.Attr("style", string.Join(';', styles));

            // 清除链接
            if (tagName == "a" && (setting.RemoveLink || string.IsNullOrWhiteSpace(element.Attr("href"))))
            {
                foreach (var item in element.Children)
                {
                    item.RemoveAttr("style");
                    element.Before(item);
                }

                element.Remove();
            }

            foreach (var item in children)
            {
                ProcessHtml(item, setting);
            }
        }
    }
}
