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 cDataHistoryConfigClientAgent : IConfigNodeValidation
    {
        public bool IsValid { get; set; } = false;

        public cDataHistoryConfigSqlConnection Connection { get; private set; } = null;

        public Uri ServerUri { get; private set; } = null;

        public int MaxDeviceAge { get; private set; } = 30;

        public Uri ApiPath { get; private set; } = null;

        public cCredential ApiCredential { get; private set; } = null;

        public string ApiSecret { get; private set; } = null;

        public string Organization { get; private set; } = null;

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

        public List<cDataHistoryConfigLocalAccountAssignment> localAccountAssignments = null;


        internal cDataHistoryConfigClientAgent(XmlElement XNode, Dictionary<string, cCredential> Credentials, Dictionary<string, cDataHistoryConfigDbConnection> DbConnections, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                if (!(XNode.SelectSingleNode("ClientAgent") is XmlElement XNode2))
                {
                    Parser.AddMessage(XNode, $"The root element <{XNode.Name}> does not have a <ClientAgent> element.");
                    return;
                }

                Parser.EnterElement("ClientAgent");

                try
                {
                    var strConnection = cXmlParser.GetStringFromXmlAttribute(XNode2, "DB-Connection");
                    if (string.IsNullOrWhiteSpace(strConnection))
                    {
                        Parser.AddMessage(XNode, $"The element <{XNode2.Name}> does not have a 'DB-Connection' attribute.");
                        return;
                    }

                    if (!DbConnections.TryGetValue(strConnection, out var Conn))
                    {
                        Parser.AddMessage(XNode, $"Could not find a DB connection '{strConnection}' in element <{XNode2.Name}>.");
                        return;
                    }

                    if (!(Conn is cDataHistoryConfigSqlConnection SqlConn))
                    {
                        Parser.AddMessage(XNode, $"The DB connection '{strConnection}' in element <{XNode2.Name}> has to be a  SQL connection.");
                        return;
                    }

                    var strServerUri = cXmlParser.GetStringFromXmlAttribute(XNode2, "Server-Url", "");
                    if (!Uri.TryCreate(strServerUri, UriKind.Absolute, out var _uri))
                    {
                        Parser.AddMessage(XNode, $"The attribute 'Server-Url' in element <{XNode2.Name}> is not a valid URL.");
                        return;
                    }
                    ServerUri = _uri;

                    strServerUri = cXmlParser.GetStringFromXmlAttribute(XNode2, "Api-Path", "api/management");
                    if (!Uri.TryCreate(strServerUri, UriKind.Relative, out _uri))
                    {
                        Parser.AddMessage(XNode, $"The attribute 'Api-Path' in element <{XNode2.Name}> is not a valid URL path.");
                        return;
                    }
                    ApiPath = _uri;


                    Organization = cXmlParser.GetStringFromXmlAttribute(XNode2, "Organization");

                    MaxDeviceAge = cXmlParser.GetIntegerFromXmlAttribute(XNode2, "MaxDeviceAge", 30);
                    if (MaxDeviceAge <= 0)
                    {
                        Parser.AddMessage(XNode, $"The attribute 'MaxDeviceAge' in element <{XNode2.Name}> is not a valid positive number of days.");
                        return;
                    }
                    Connection = SqlConn;

                    var strCredential = cXmlParser.GetStringFromXmlAttribute(XNode2, "Api-Credential");
                    if (string.IsNullOrWhiteSpace(strCredential))
                    {
                        Parser.AddInvalidAttribute(XNode, null, "Api-Credential");
                        return;
                    }

                    if (!Credentials.TryGetValue(strCredential, out var _Cred))
                    {
                        Parser.AddMessage(XNode, $"The credential attribute value '{strCredential}' of the element <{XNode.Name}> coud not be resolved.");
                        return;
                    }
                    ApiCredential = _Cred;
                    ApiSecret = cSecurePassword.Instance.Encode(_Cred.NwCredential.Password);

                    ScanTiming = new cDataHistoryScanTiming(XNode2, TimeSpan.FromHours(1), TimeSpan.FromMinutes(10), Parser);

                    localAccountAssignments = cDataHistoryConfigLocalAccountAssignment.LoadFromXml(XNode2, Parser);

                    IsValid = true;

                }
                finally
                {
                    Parser.LeaveElement("ClientAgent");
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }
        }

    }

    public class cDataHistoryConfigLocalAccountAssignment : IConfigNodeValidation
    {
        public bool IsValid { get; set; } = false;
        public string Domain = null;
        public string DomainDns = null;
        public string RegExFilter = null;
        public string AccountMask = null;

        internal cDataHistoryConfigLocalAccountAssignment(XmlElement XNode, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                Domain = cXmlParser.GetStringFromXmlAttribute(XNode, "Domain");
                if (string.IsNullOrEmpty(Domain))
                {
                    Parser.AddInvalidAttribute(XNode, null, "Domain", LogLevels.Warning);
                    return;
                }

                RegExFilter = cXmlParser.GetStringFromXmlAttribute(XNode, "RegExFilter");
                AccountMask = cXmlParser.GetStringFromXmlAttribute(XNode, "AccountMask");
                if (!string.IsNullOrEmpty(AccountMask) && !AccountMask.Contains("*"))
                {
                    Parser.AddMessage(XNode, $"The <{XNode.Name}> element with Domain='{Domain}' has no '*' placeholder in the 'AccountMask' attribute.", LogLevels.Warning);
                    return;
                }

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

        internal static List<cDataHistoryConfigLocalAccountAssignment> LoadFromXml(XmlElement XNode, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                var XDataClusters = XNode.SelectNodes("Local-Account-Assignment");
                if (XDataClusters == null || XDataClusters.Count <= 0)
                    return null;

                Parser.EnterElement("Local-Account-Assignment");
                var RetVal = new List<cDataHistoryConfigLocalAccountAssignment>(XDataClusters.Count);
                try
                {
                    foreach (XmlNode XNode2 in XDataClusters)
                    {
                        if (!(XNode2 is XmlElement XDataCluster))
                            continue;

                        var LocalAssignment = new cDataHistoryConfigLocalAccountAssignment(XDataCluster, Parser);
                        if ((LocalAssignment != null) && (LocalAssignment.IsValid))
                        {
                            RetVal.Add(LocalAssignment);
                        }

                        Parser.SelectElementNext();
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    Parser.LeaveElement("Local-Account-Assignment");
                }

                if (RetVal.Count > 0)
                    return RetVal;

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

            return null;
        }


    }
}
