using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Xmind2UnityConfigCore
{
    public static class XMindTypeExt
    {
        public static int ToUnity(string xmindPath, string outDirPath,bool isDebug)
        {
            if (!File.Exists(xmindPath))
            {
                Console.WriteLine($"{xmindPath} is not exist!!");
                return -1;
            }
            if (string.IsNullOrEmpty(outDirPath))
                outDirPath = System.IO.Path.GetDirectoryName(xmindPath);

            //var zipArchive = ZipFile.o(openFileDialog.FileName);
            //zipArchive.

            //解压缩的临时路径
            string tempPath = System.IO.Path.Combine(
                    System.IO.Path.GetTempPath(),
                    System.IO.Path.GetFileNameWithoutExtension(xmindPath));

            if (Directory.Exists(tempPath))
                Directory.Delete(tempPath, true);

            ZipFile.ExtractToDirectory(xmindPath, tempPath);

            string filePath = System.IO.Path.Combine(tempPath, "content.json");
            string json = File.ReadAllText(filePath);

            var xmind = JsonConvert.DeserializeObject<XMindRootTopic[]>(json);

            //转义title
            //string unescape = System.Text.RegularExpressions.Regex.Unescape(str);
            if (isDebug)
            {
                json = Newtonsoft.Json.JsonConvert.SerializeObject(xmind, Formatting.Indented);
                Console.WriteLine(json);
            }

            var rootTopic = xmind.First().rootTopic;
            //把全部注解删除
            MakeTopicLegal(rootTopic);


            ToUnity(rootTopic, outDirPath);
            Console.WriteLine($@"success!!! out to {System.IO.Path.Combine(outDirPath, "unity")}");
            return 0;
        }

        static string MakeTitleLegal(string title) 
        {
            //把全部 中文的 （） 替换为 英文的 ()
            title = new string(title.Select((c) =>
            {
                switch (c)
                {
                    case '（':
                        return '(';
                    case '）':
                        return ')';
                    case '“':
                        return '"';
                    case '”':
                        return '"';
                    case '\n':
                        return ' ';
                    default:
                        return c;
                }
            }).ToArray());

            //删除全部注解
            Regex regex_instruction = new Regex(@"\([\s\S]*\)");

            title = regex_instruction.Replace(title, "");

            title  = title.Trim();

            //全部注解删除后，什么也没有
            if (string.IsNullOrEmpty(title))
                return null;

            return title;
        }
        static void MakeTopicLegal(XMindTopic topic)
        {
            topic.title = MakeTitleLegal(topic.title);
            if (topic.title == null)
                return;

            if (
                topic.children == null
                || topic.children.attached == null
                || topic.children.attached.Count() == 0
                )
                return;
            foreach (var t in topic.children.attached)
            {
                MakeTopicLegal(t);
            }
            topic.children.attached.RemoveAll(t => t.title == null);
        }
        static void ToUnity(XMindTopic rootTopic, string path)
        {
            path = System.IO.Path.Combine(path, "unity");
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            //register \ntype=\"IUnityContainer\"\nname=\"root\"\n(根容器)

            //生成relationship.json

            RelationShip relationShip = ToRelationShip(rootTopic, path);
            string json = Newtonsoft.Json.JsonConvert.SerializeObject(relationShip, Newtonsoft.Json.Formatting.Indented);
            File.WriteAllText(System.IO.Path.Combine(path, "relationship.json"), json);

        }


        static RelationShip ToRelationShip(XMindTopic topic, string path)
        {
            RelationShip relationShip = new RelationShip();

            var x_root = ToXElement(topic.title);

            string name = x_root.Attribute("name").Value;

            relationShip.Name = name;

            foreach (var subTopic in topic.children.attached)
            {
                if (subTopic.title.Contains("register")
                    && subTopic.title.Contains("type=\"IUnityContainer\""))
                {
                    //这是子容器
                    var subRelationShip = ToRelationShip(subTopic, path);
                    relationShip.Children.Add(subRelationShip);
                }
                else 
                {
                    //这是config文件
                    //var ss = subTopic.title.Split('\n');
                    string filename = subTopic.title;//  ss[0].Trim();
                    relationShip.Path.Add(filename);
                    string filepath = System.IO.Path.Combine(path, filename);
                    //创建 xxx.config 文件 
                    ToConfig(subTopic.children.attached, filepath);
                }

            }
            return relationShip;
        }


        static XElement ToXElement(string title)
        {
            if (string.IsNullOrEmpty(title))
                return null;
            
            title = title.Trim();
            
            //什么也没有
            if (string.IsNullOrEmpty(title))
                return null;

            Regex regex_xml = new Regex(@"\<[\s\S]*/\>");
            var match = regex_xml.Match(title);
            if (match.Success)
            {
                //它就是标准的xml格式,直接转换
                return XElement.Parse(title);
            }

            //头尾添加< />
            title = $@"<{title} />";
            return XElement.Parse(title);
        }
        static XElement ToXElement(XMindTopic topic)
        {
            XElement x = ToXElement(topic.title);
            if (x == null)
                return null;

            if (topic.children == null || topic.children.attached == null)
                return x;

            foreach (var sub in topic.children.attached)
            {
                var x_sub = ToXElement(sub);
                if (x_sub == null)
                    continue;
                x.Add(x_sub);
            }
            return x;
        }

        static void ToConfig(List<XMindTopic> topics, string filepath)
        {
            XDocument xdoc = new XDocument();
            //创建根元素
            XElement x_configuration = new XElement("configuration");
            //把根元素添加到文件中
            xdoc.Add(x_configuration);

            XElement x_configSections = new XElement("configSections");
            x_configuration.Add(x_configSections);

            XElement x_section = new XElement("section");
            x_configSections.Add(x_section);
            x_section.Add(
                new XAttribute("name", "unity"),
                new XAttribute("type", "Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration")
                );


            //XNamespace ns = "http://schemas.microsoft.com/practices/2010/unity";
            XElement x_unity = new XElement("unity");// (ns+"unity");
            x_configuration.Add(x_unity);


            //找出全部assembly 与 alias

            var assemblies_topics = topics.FindAll( t => !string.IsNullOrEmpty(t.title) && t.title.Trim().StartsWith("assembly"));
            foreach (var assemblies_topic in assemblies_topics)
            {
                foreach (var assembly_topic in assemblies_topic.children.attached)
                {
                    XElement x_assembly = new XElement("assembly");
                    x_unity.Add(x_assembly);

                    if (string.IsNullOrEmpty(assembly_topic.title))
                        throw new Exception($"filepath={filepath} error!!!!  because of \"assembly_topic.title==null\"");


                    x_assembly.Add(new XAttribute("name", assembly_topic.title));

                    foreach (var namespace_topic in assembly_topic.children.attached)
                    {
                        XElement x_namespace = new XElement("namespace");
                        x_unity.Add(x_namespace);

                        if (string.IsNullOrEmpty(namespace_topic.title))
                            throw new Exception($"filepath={filepath} error!!!!  because of \"namespace_topic.title==null\"");

                        x_namespace.Add(new XAttribute("name", namespace_topic.title));
                    }
                }
            }

            var aliass_topics = topics.FindAll(t => t.title.Trim().StartsWith("alias"));
            foreach (var aliass_topic in aliass_topics)
            {
                foreach (var alias_topic in aliass_topic.children.attached)
                {
                    if (string.IsNullOrEmpty(alias_topic.title))
                        throw new Exception($"filepath={filepath} error!!!!  because of \"alias_topic.title==null\"");

                    if (alias_topic.children == null)
                        throw new Exception($"filepath={filepath} error!!!!  because of \"alias_topic.children == null\"");

                    if (alias_topic.children.attached == null)
                        throw new Exception($"filepath={filepath} error!!!!  because of \"alias_topic.children.attached == null\"");

                    if (alias_topic.children.attached.Count()!=1)
                        throw new Exception($"filepath={filepath} error!!!!  because of \"alias_topic.children.attached.Count()!=1\"");

                    XElement x_alias = new XElement("alias");
                    x_unity.Add(x_alias);
                    x_alias.Add(new XAttribute("alias", alias_topic.title));
                    x_alias.Add(new XAttribute("type", alias_topic.children.attached[0].title));
                }
            }


            topics.RemoveAll(t => t.title.Trim().StartsWith("assembly") || t.title.Trim().StartsWith("alias"));



            //容器
            XElement x_container = new XElement("container");
            x_unity.Add(x_container);

            foreach (var topic in topics)
            {
                var x = ToXElement(topic);
                if (x == null)
                    continue;
                x_container.Add(x);
            }

            //保存
            xdoc.Save(filepath);
        }
    }
}
