using C4IT.Logging;
using C4IT.Security;
using C4IT.XML;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using static C4IT.Logging.cLogManager;

namespace C4IT.DataHistoryProvider
{
    public class cDataHistoryConfigNexthink : IConfigNodeValidation
    {
        public bool IsValid { get; set; } = false;

        public cDataHistoryScanTiming ScanTiming { get; private set; } = null;

        public Dictionary<string, cDataHistoryNxtPortal> Portals = new Dictionary<string, cDataHistoryNxtPortal>();

        internal cDataHistoryConfigNexthink(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {

                var XNode2 = XNode.SelectSingleNode("Nexthink");
                if (!(XNode2 is XmlElement XNexthink))
                {
                    return;
                }

                Parser.EnterElement("Nexthink");

                try
                {
                    ScanTiming = new cDataHistoryScanTiming(XNexthink, TimeSpan.FromHours(24), TimeSpan.FromMinutes(10), Parser);

                    Portals = cDataHistoryNxtPortal.LoadFromXml(XNexthink, Credentials, Parser);

                    if (Portals != null && Portals.Count > 0)
                        IsValid = true;
                }
                finally
                {
                    Parser.LeaveElement("Nexthink");
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }
        }
    }

    public class cDataHistoryNxtPortal : cConfigNodeNamed
    {
        public string Address { get; set; }

        public cCredential Credential { get; set; }

        public bool IsCloud { get; set; } = false;

        public Dictionary<string, cDataHistoryNxtEngine> Engines = new Dictionary<string, cDataHistoryNxtEngine>();


        internal cDataHistoryNxtPortal(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser) :
            base(XNode, Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                if (!IsValid)
                    return;

                IsValid = false;

                Address = cXmlParser.GetStringFromXmlAttribute(XNode, "Address");
                if (string.IsNullOrWhiteSpace(Address))
                {
                    Parser.AddInvalidAttribute(XNode, Name, "Address");
                    return;
                }

                var _strCredential = cXmlParser.GetStringFromXmlAttribute(XNode, "Credential");
                if (string.IsNullOrWhiteSpace(_strCredential))
                {
                    Parser.AddInvalidAttribute(XNode, Name, "Credential");
                    return;
                }
                if (!Credentials.TryGetValue(_strCredential, out var _Cred))
                {
                    Parser.AddMessage(XNode, $"Could not find the credential '{_strCredential}' in element <{XNode.Name}>");
                    return;
                }
                Credential = _Cred;

                IsCloud = cXmlParser.GetBoolFromXmlAttribute(XNode, "IsCloud");

                Engines = cDataHistoryNxtEngine.LoadFromXml(XNode, this, Parser);

                IsValid = true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }
        }

        internal static Dictionary<string, cDataHistoryNxtPortal> LoadFromXml(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                var lstXNode = XNode.SelectNodes("Nxt-Portal");
                if (lstXNode == null || lstXNode.Count == 0)
                {
                    Parser.AddMessage(XNode, "Could not find a valid <Nxt-Portal> element.");
                    return null;
                }

                Parser.EnterElement("Nxt-Portal");
                try
                {
                    var RetVal = new Dictionary<string, cDataHistoryNxtPortal>(lstXNode.Count);
                    foreach (var XENtry in lstXNode)
                    {
                        if (!(XENtry is XmlElement XPortal))
                            continue;

                        var Po = new cDataHistoryNxtPortal(XPortal, Credentials, Parser);
                        if (Po != null && Po.IsValid)
                            RetVal.Add(Po.Name, Po);

                        Parser.SelectElementNext();
                    }

                    return RetVal;
                }
                finally
                {
                    Parser.LeaveElement("Nxt-Portal");
                }

            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

            return null;
        }

    }

    public class cDataHistoryNxtEngine : cConfigNodeNamed
    {
        public string Address { get; set; }

        public int Port { get; set; } = -1;

        internal cDataHistoryNxtEngine(XmlElement XNode, cDataHistoryNxtPortal Portal, cXmlParser Parser) :
            base(XNode, Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                if (!IsValid)
                    return;

                IsValid = false;

                Address = cXmlParser.GetStringFromXmlAttribute(XNode, "Address");
                if (string.IsNullOrWhiteSpace(Address))
                {
                    Parser.AddInvalidAttribute(XNode, Name, "Address");
                    return;
                }

                Port = 1671;
                if (Portal.IsCloud)
                    Port = 443;
                Port = cXmlParser.GetIntegerFromXmlAttribute(XNode, "Port", Port);

                IsValid = true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

        }

        internal static Dictionary<string, cDataHistoryNxtEngine> LoadFromXml(XmlElement XNode, cDataHistoryNxtPortal Portal, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                var lstXNode = XNode.SelectNodes("Nxt-Engine");
                if (lstXNode == null || lstXNode.Count == 0)
                {
                    Parser.AddMessage(XNode, "Could not find a valid <Nxt-Engine> element.");
                    return null;
                }

                Parser.EnterElement("Nxt-Engine");
                try
                {
                    var RetVal = new Dictionary<string, cDataHistoryNxtEngine>(lstXNode.Count);
                    foreach (var XENtry in lstXNode)
                    {
                        if (!(XENtry is XmlElement XPortal))
                            continue;

                        var En = new cDataHistoryNxtEngine(XPortal, Portal, Parser);
                        if (En != null && En.IsValid)
                            RetVal.Add(En.Name, En);

                        Parser.SelectElementNext();
                    }

                    return RetVal;
                }
                finally
                {
                    Parser.LeaveElement("Nxt-Engine");
                }

            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

            return null;
        }

    }
}
