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

namespace ZionRobot.Models.Source
{
    public class Action
    {
        private string where;
        private string value;

        public string Name { get; set; }

        public string Type { get; set; }

        public string Check { get; set; }

        public string Regex { get; set; }

        public string Replace { get; set; }

        public string Attribute { get; set; }

        public int MaxLength { get; set; }

        public int Index { get; set; }
        public bool Wait { get; set; }

        public bool Initialize { get; set; }

        public List<Action> InnerActions { get; set; }

        public List<Action> ResultTrue { get; set; }

        public List<Action> ResultFalse { get; set; }

        public string Where { get => where; set => this.where = value; }
        public string Value { get => value; set => this.value = value; }

        public Action()
        {
            Initialize = true;
        }

        public Action(System.Xml.XmlNode node)
        {
            try
            {
                Name = node.Attributes[@"Name"]?.Value ?? null;
                Type = node.Attributes[@"Type"]?.Value ?? null;
                Where = node.Attributes[@"Where"]?.Value ?? null;
                Check = node.Attributes[@"Check"]?.Value ?? null;
                Regex = node.Attributes[@"Regex"]?.Value ?? null;
                Replace = node.Attributes[@"Replace"]?.Value ?? null;
                Attribute = node.Attributes[@"Attribute"]?.Value ?? null;
                MaxLength = node.Attributes[@"MaxLength"] != null ? int.Parse(node.Attributes[@"MaxLength"]?.Value) : 0;
                Value = node.Attributes[@"Value"]?.Value.Replace("&amp;", "&") ?? null;
                Index = node.Attributes[@"Index"] != null ? int.Parse(node.Attributes[@"Index"].Value) : -1;
                Wait = node.Attributes[@"Wait"] != null ? bool.Parse(node.Attributes[@"Wait"].Value) : true;

                InnerActions = new List<Action>();

                foreach (System.Xml.XmlNode n in node.SelectNodes(@"Action"))
                {
                    InnerActions.Add(new Action(n));
                }

                ResultTrue = new List<Action>();

                foreach(System.Xml.XmlNode action in node.SelectNodes(@"ResultTrue/Action"))
                {
                    ResultTrue.Add(new Action(action));
                }

                ResultFalse = new List<Action>();

                foreach (System.Xml.XmlNode action in node.SelectNodes(@"ResultFalse/Action"))
                {
                    ResultFalse.Add(new Action(action));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public System.Xml.XmlElement AppendTo(System.Xml.XmlDocument doc)
        {
            System.Xml.XmlElement root = doc.CreateElement(@"Action");

            if(Name != null)
                root.SetAttribute(@"Name", Name);

            if(Type != null)
                root.SetAttribute(@"Type", Type);

            if(Where != null)
                root.SetAttribute(@"Where", Where);

            if(Check != null)
                root.SetAttribute(@"Check", Check);

            if (Regex != null)
                root.SetAttribute(@"Regex", Regex);

            if (Replace != null)
                root.SetAttribute(@"Replace", Replace);

            if (Attribute != null)
                root.SetAttribute(@"Attribute", Attribute);

            if(Value != null)
                root.SetAttribute(@"Value", Value);

            if (MaxLength > 0)
                root.SetAttribute(@"MaxLength", MaxLength.ToString());

            if(!Wait)
                root.SetAttribute(@"Wait", Wait.ToString());

            if(Index >= 0)
                root.SetAttribute(@"Index", Index.ToString());

            if(InnerActions.Count > 0)
            {
                System.Xml.XmlElement eLoop = doc.CreateElement(@"Loop");
                InnerActions.ForEach(innerAction =>
                {
                    eLoop.AppendChild(innerAction.AppendTo(doc));
                });
                root.AppendChild(eLoop);
            }

            if(ResultTrue.Count > 0)
            {
                System.Xml.XmlElement resultTrue = doc.CreateElement(@"ResultTrue");
                InnerActions.ForEach(innerAction =>
                {
                    resultTrue.AppendChild(innerAction.AppendTo(doc));
                });
                root.AppendChild(resultTrue);
            }

            if(ResultFalse.Count > 0)
            {
                System.Xml.XmlElement resultFalse = doc.CreateElement(@"ResultFalse");
                InnerActions.ForEach(innerAction =>
                {
                    resultFalse.AppendChild(innerAction.AppendTo(doc));
                });
                root.AppendChild(resultFalse);
            }

            return root;
        }

        public string ReplaceWithDictionary(string value, Dictionary<string, string> dictionaryValues)
        {
            string result = value;
            List<string> parts = System.Text.RegularExpressions.Regex.Matches(value, @"\{[^\}]*\}")
                                    .Cast<Match>().Select(m => m.Value).ToList();

            parts.ForEach(part =>
            {
                string temp = part.Trim('{').Trim('}');
                string add = string.Empty;
                if (dictionaryValues.ContainsKey(temp))
                {
                    //TODO TIRAR O CHUMBO
                    if (this.Where == @"input[id=data_da_disponibilizStr]" &&
                        dictionaryValues[@"SearchElements.Fields.Tipo"] == @"Publicação")
                    {
                        add += getBusinessDay(DateTime.Parse(dictionaryValues[temp]), -1).ToString(@"dd/MM/yyyy");
                    }
                    else if (this.Where == @"input[id=data_de_publicacaoStr]" &&
                         (dictionaryValues[@"SearchElements.Fields.Tipo"] == @"Disponibilização"
                            ||
                         dictionaryValues[@"SearchElements.Fields.Tipo"] == @"Divulgação")
                         )
                    {
                        add += getBusinessDay(DateTime.Parse(dictionaryValues[temp]), 1).ToString(@"dd/MM/yyyy");
                    }
                    else
                    {
                        add += dictionaryValues[temp];
                    }

                    if (this.Replace != null)
                    {
                        this.Replace.Split(';').ToList().ForEach(x =>
                        {
                            var p = x.Split(',');
                            add = System.Text.RegularExpressions.Regex.Replace(add, p[0], p[1]);
                        });
                        
                    }
                }


                /*if (add != string.Empty)
                    result += add;
                else
                    result += System.Text.RegularExpressions.Regex.Replace(part, @"amp;", string.Empty);*/

                result = result.Replace(part, add.Replace(@"&gt;", @">"));
            });

            result = result != string.Empty ? result : value;

            return this.MaxLength > 0 ? result.Substring(0, Math.Min(result.Length, this.MaxLength)) : result;
        }


        public string ReplaceValue(string value, Dictionary<string, string> dictionaryValues)
        {
            string result = string.Empty;
            List<string> parts = System.Text.RegularExpressions.Regex.Matches(value, @"\{[^\}]*\}|([:=\[\(\{]{0}[a-zA-Z0-9_%@\-\.\/:?=&;]{1,})")
                                    .Cast<Match>().Select(m => m.Value).ToList();
            parts.ForEach(part =>
            {
                string temp = part.Trim('{').Trim('}');
                string add = string.Empty;

                if (System.Text.RegularExpressions.Regex.IsMatch(temp, @"\$_Now"))
                {
                    DateTime dateNow = DateTime.Now;
                    int day = 0;
                    //verificar se tem condição Now>16?2:1 => {Now>16} {2:1}
                    string[] p = temp.Split('?');

                    //quando não tem doncição
                    if (p.Count() == 1)
                    { //verificar se tem '.' Now.1 
                        if (System.Text.RegularExpressions.Regex.IsMatch(p[0], @"\."))
                        {
                            day = int.Parse(temp.Split('.').Last());
                        }
                    }
                    else
                    {
                        string @operator =
                                System.Text.RegularExpressions.Regex.Matches(p[0], @"([!=<>]{1,2}[<>=]?)")
                                .Cast<Match>().Select(match => match.Value).First();

                        //Ex: p[0] = Now>16 => {Now}{16}
                        string[] s = p[0].Split(new string[] { @operator }, StringSplitOptions.RemoveEmptyEntries);

                        int hours = int.Parse(s[1]);

                        //Ex: p[1] = 2:1 => {2}{1}
                        string[] days = p[1].Split(':');

                        if (@operator == @"==" && dateNow.Hour == hours ||
                            @operator == @"!=" && dateNow.Hour != hours ||
                            @operator == @"<=" && dateNow.Hour <= hours ||
                            @operator == @">=" && dateNow.Hour >= hours ||
                            @operator == @">" && dateNow.Hour > hours ||
                            @operator == @"<" && dateNow.Hour < hours)
                        {
                            day = int.Parse(days[0]);
                        }
                        else
                        {
                            day = int.Parse(days[1]);
                        }
                    }
                    add = day == 0 ? dateNow.ToString("dd/MM/yyyy") : getBusinessDay(DateTime.Now, day).ToString("dd/MM/yyyy");
                }

                if (dictionaryValues.ContainsKey(temp))
                {
                    //TODO TIRAR O CHUMBO
                    if (this.Where == @"input[id=data_da_disponibilizStr]" &&
                        dictionaryValues[@"SearchElements.Fields.Tipo"] == @"Publicação")
                    {
                        add += getBusinessDay(DateTime.Parse(dictionaryValues[temp]), -1).ToString(@"dd/MM/yyyy");
                    }
                    else if (this.Where == @"input[id=data_de_publicacaoStr]" &&
                         (dictionaryValues[@"SearchElements.Fields.Tipo"] == @"Disponibilização"
                            ||
                         dictionaryValues[@"SearchElements.Fields.Tipo"] == @"Divulgação")
                         )
                    {
                        add += getBusinessDay(DateTime.Parse(dictionaryValues[temp]), 1).ToString(@"dd/MM/yyyy");
                    }
                    else
                    {
                        add += dictionaryValues[temp];
                    }
                }

                if (add != string.Empty)
                    result += add;
                else
                    result += System.Text.RegularExpressions.Regex.Replace(part, @"amp;", string.Empty);
            });

            result = result != string.Empty ? result : value;

            return this.MaxLength > 0 ? result.Substring(0, Math.Min(result.Length, this.MaxLength)) : result;
        }


        private DateTime getBusinessDay(DateTime dateTime, int day)
        {
            DateTime currentDay = dateTime;

            while (true)
            {
                currentDay = currentDay.AddDays(day);

                if (Helpers.Shift.isDuringTheWeek(currentDay))
                {
                    break;
                }
            }
            return currentDay;
        }
    }
}