using Avalonia.Threading;
using EdTestEmulator.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;

namespace EdTestEmulator.Services
{
    internal class MessageProcessingService
    {
        private ICollection<ProcedureRow> _procedures;
        private ICollection<MessageRow> _messages;
        private IDictionary<MessageRow, string> _xmlMessages;

        private FileSystemWatcher _watcher;
        private string _dirPath;

        public MessageProcessingService(ICollection<ProcedureRow> procedures, ICollection<MessageRow> messages, IDictionary<MessageRow,string> _xmlMessageMap, string directory) 
        {
            this._procedures = procedures;
            this._messages = messages;
            this._xmlMessages = _xmlMessageMap;

            if (!Directory.Exists(directory))
                Directory.CreateDirectory(directory);

            _dirPath = directory;
            _watcher = new FileSystemWatcher(directory);
            _watcher.EnableRaisingEvents = true;
            _watcher.Created += _watcher_Created;
        }

        private void _watcher_Created(object sender, FileSystemEventArgs e)
        {
            Task.Delay(300).Wait();
            var fileContent = File.ReadAllText(e.FullPath);

            var doc = new XmlDocument();

            doc.LoadXml(fileContent);

            var elementList = doc.GetElementsByTagName("Header");

            if (elementList.Count == 0) elementList = doc.GetElementsByTagName("env:Header");

            XmlNode header;

            if (elementList.Count > 0)
            {
                header = elementList.Item(0);

                var edHeader = header.ChildNodes.OfType<XmlNode>().FirstOrDefault(x=>x.Name.Contains("EDHeader"));

                var routingInf = header.ChildNodes.OfType<XmlNode>().FirstOrDefault(x => x.Name.Contains("RoutingInf"));

                var envelopeId = string.Empty;
                var initEnvelopeId = string.Empty;
                var messageType = string.Empty;
                var procUuid = string.Empty;

                if (routingInf is not null)
                {
                    envelopeId = routingInf.OfType<XmlNode>().FirstOrDefault(x=>x.Name.Contains("EnvelopeID"))?.InnerText;
                    initEnvelopeId = routingInf.OfType<XmlNode>().FirstOrDefault(x => x.Name.Contains("InitialEnvelopeID"))?.InnerText;

                    Debug.WriteLine(envelopeId);
                    Debug.WriteLine(initEnvelopeId);
                }

                if (edHeader is not null)
                {
                    messageType = edHeader.OfType<XmlNode>().FirstOrDefault(x => x.Name.Contains("MessageType"))?.InnerText;
                    procUuid = edHeader.OfType<XmlNode>().FirstOrDefault(x => x.Name.Contains("ProccessID"))?.InnerText;
                    Debug.WriteLine(messageType);
                }

                if (messageType == "ED.11001")
                {
                    procUuid = CreateProcedure(envelopeId, doc);

                    SendMessageArrivedNotify(procUuid,doc);

                    SendSuccessProcCreateMessage(procUuid, envelopeId);

                    SendAwaitDocsMessage(procUuid, envelopeId);
                    return;
                }

                if (messageType == "CMN.11023")
                {
                    SendMessageArrivedNotify(procUuid, doc);
                    SendMessageDT(procUuid,doc);
                }
            }
        }

        private void SendMessageDT(string procUuid, XmlDocument doc)
        {
            var newMessage = new MessageRow();

            //_procedures.First(x => x.ProcedureUUID == procUuid).Type = "ДТ";

            newMessage.ProcedureUUID = procUuid;
            newMessage.MessageUUID = Guid.NewGuid().ToString();
            newMessage.Date
                = DateTime.Now;

            newMessage.Type = "ED.11006";
            newMessage.Description = "Уведомление об оформлении ДТ в рамках технологии удаленного выпуска.";

            Dispatcher.UIThread.Invoke(new Action(() =>
            {
                _messages.Add(newMessage);
            }));


            var esdOut = doc.GetElementsByTagName("Body")[0].ChildNodes[0].ChildNodes[3].ChildNodes[0].ChildNodes[1].ChildNodes[0].ChildNodes[0].ChildNodes[3].ChildNodes[0];

            _xmlMessages.Add(newMessage,esdOut.OuterXml);
        }

        private void SendMessageArrivedNotify(string procUuid, XmlDocument doc)
        {
            var newMessage = new MessageRow();

            newMessage.ProcedureUUID = procUuid;
            newMessage.MessageUUID = Guid.NewGuid().ToString();
            newMessage.Date
                = DateTime.Now;

            newMessage.Type = "CMN.00002";
            newMessage.Description = "Уведомление о получении сообщения.";

            Dispatcher.UIThread.Invoke(new Action(() =>
            {
                _messages.Add(newMessage);
            }));
        }

        private void SendAwaitDocsMessage(string procUuid, string? envelopeId)
        {
            var newMessage = new MessageRow();

            newMessage.ProcedureUUID = procUuid;
            newMessage.MessageUUID = Guid.NewGuid().ToString();
            newMessage.Date
                = DateTime.Now;

            newMessage.Type = "ED.00003";
            newMessage.Description = "Требование на представление электронных документов.";

            Dispatcher.UIThread.Invoke(new Action(() =>
            {
                _messages.Add(newMessage);
            }));
        }

        private void SendSuccessProcCreateMessage(string procUuid, string? envelopeId)
        {
            var newMessage = new MessageRow();

            newMessage.ProcedureUUID = procUuid;
            newMessage.MessageUUID = Guid.NewGuid().ToString();
            newMessage.Date
                = DateTime.Now;

            newMessage.Type = "ED.11002";
            newMessage.Description = "Уведомление об открытии процедуры декларирования.";
            Dispatcher.UIThread.Invoke(new Action(() =>
            {
                _messages.Add(newMessage);
            }));
        }

        private string CreateProcedure(string? envelopeId, XmlDocument doc)
        {
            var newUuid = Guid.NewGuid();

            var procedure = new ProcedureRow();

            procedure.ProcedureUUID = newUuid.ToString();

            var reqOpenProc = doc.GetElementsByTagName("ReqOpenProc")[0];

            var declarant = reqOpenProc.OfType<XmlNode>().FirstOrDefault(x => x.Name.Contains("Declarant"));

            var orgName = declarant.OfType<XmlNode>().FirstOrDefault(x => x.Name.Contains("OrganizationName")).InnerText;

            procedure.AwaitStatus = 1;
            procedure.RequiredDocs = 1;
            procedure.Organization = orgName;
            procedure.DateStart = DateTime.Now;

            var appVer = doc.GetElementsByTagName("app:SoftVersion").Count > 0 ? doc.GetElementsByTagName("app:SoftVersion")[0] : doc.GetElementsByTagName("SoftVersion")[0];

            procedure.EdVersion = appVer.InnerText;

            Dispatcher.UIThread.Invoke(new Action(() =>
            {
                _procedures.Add(procedure);
            }));

            return newUuid.ToString();
        }
    }
}
