using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using HtmlAgilityPack;

namespace InABox.Core
{
    public static class HTMLUtils
    {
        
        /// <summary>
        /// Takes a HTML Snippet and converts it to full HTML.
        /// This is used to convert Fast-Reports "html-enabled" text to Syncfusion RichTextEditor html.
        /// </summary>
        /// <param name="text">The html snippet (no <head> or <body> tags, paragraphs represented by line breaks</param>
        /// <returns>Properly formed HTM suitable for editing</returns>
        public static string TextToHtml(string text)
        {
            var result = text;
            if (!result.Contains("<html>"))
            {
                var lines = result.Split("\n").Select(l => $"<p>{(string.IsNullOrWhiteSpace(l) ? "&nbsp;" : l)}</p>").ToList();
                while (string.Equals(lines.LastOrDefault(),$"<p>&nbsp;</p>"))
                    lines.RemoveAt(lines.Count-1);
                result = $"<html><body>{string.Join("\n",lines)}</body></html>";
            }
            var doc = new HtmlDocument();
            doc.LoadHtml(result);
            HtmlNode? head = null;
            var htmlnode = doc.DocumentNode.SelectSingleNode("//html");
            if (!htmlnode.ChildNodes.Any(x => string.Equals(x.Name, "head", StringComparison.CurrentCultureIgnoreCase)))
            {
                head = doc.CreateElement("head");
                htmlnode.PrependChild(head);
            }
            head = doc.DocumentNode.SelectSingleNode("//head");
            if (head != null)
            {
                HtmlNode? style = null;
                if (!head.ChildNodes.Any(x =>
                        string.Equals(x.Name, "style", StringComparison.CurrentCultureIgnoreCase)))
                {
                    style = doc.CreateElement("style");
                    head.PrependChild(style);
                }
                else
                    style = head.ChildNodes["style"];
                style.InnerHtml = "p { margin: 0px 0px 0px 0px; }";
            }
            return doc.DocumentNode.OuterHtml;
        }

        /// <summary>
        /// Converts HTML data to Fast-Reports compatible "html-enabled" text
        /// Will dump tags that Fast-Reports cannot display
        /// </summary>
        /// <param name="html">The HTML data to be processed</param>
        /// <returns>Text Suitable for printing using Fast-Reports</returns>
        public static string HtmlToText(string html)
        {
            Dictionary<string, string> _replacements = new Dictionary<string, string>()
            {
                { "\n", "" },
                { "\r", "" },
                { "<p[^>]*>", "" },
                { "</p[^>]*>", "\r\n" },
            };
                
            var doc = new HtmlDocument();
            doc.LoadHtml(html);

            ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-style","italic", "i"));
            ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "text-decoration","underline", "u"));
            ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-weight","bold", "b"));
            ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-size","(.*?)", ""));
            ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-family","(.*?)", ""));
            ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "background","(.*?)", ""));

                
            string result = doc.DocumentNode.SelectSingleNode("//body").InnerHtml; 
                
            foreach (var _key in _replacements.Keys)
                result = Regex.Replace(result, _key, _replacements[_key]);
            var lines = result.Split("\r\n").ToList();
            while (string.IsNullOrWhiteSpace(lines.LastOrDefault()))
                lines.RemoveAt(lines.Count-1);
            return string.Join("\r\n", lines);
        }
        
        private static void ProcessNode(HtmlNode node, Action<HtmlNode> action)
        {
            if (node.Name.ToLower() == "span")
                action(node);
            foreach (var _child in node.ChildNodes)
                ProcessNode(_child,action);
        }
        
        private static void ReplaceAttribute(HtmlNode node, string attribute, string value, string tag)
        {
            var _value = $"{attribute}:{value};";
            var _style = node.Attributes.Contains("style") ? node.Attributes["style"] : null;
            if (_style != null)
            {
                var _oldvalue = _style.Value;
                _style.Value = Regex.Replace(_style.Value, _value, "");
                if (!string.Equals(_style.Value, _oldvalue))
                {
                    if (string.IsNullOrWhiteSpace(_style.Value))
                        node.Attributes.Remove("style");
                    if (!string.IsNullOrWhiteSpace(tag))
                    {
                        var text = node.OuterHtml;
                        node.Name = tag;
                        node.Attributes.RemoveAll();
                        node.InnerHtml = text;
                    }
                }
            }
        }
        
    }
}