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 abstract class cDataHistoryConfigDbConnection : cConfigNodeNamed
    {
        internal cDataHistoryConfigDbConnection(XmlElement XNode, cXmlParser Parser) :
            base(XNode, Parser)
        {
        }

        static public Dictionary<string, cDataHistoryConfigDbConnection> LoadListFromXml(XmlElement XNode, cXmlParser Parser, Dictionary<string, cCredential> Credentials)
        {

            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }


            var RetVal = new Dictionary<string, cDataHistoryConfigDbConnection>();

            try
            {
                XmlNode LRoot = XNode;
                LRoot = XNode.SelectSingleNode("DB-Connections");
                if (LRoot == null)
                {
                    Parser.AddMessage(XNode, $"The <{XNode.Name}> does not contain a element 'DB-Connections'", LogLevels.Error);
                    return RetVal;
                }

                Parser.EnterElement("DB-Connections");

                // cluster the db commections in a dictionary by db connection type (element node)
                var XList = LRoot.SelectNodes("SQL-Connection");
                var lstConnectionNodes = new Dictionary<string, List<XmlElement>>();
                foreach (XmlNode Entry in XList)
                {
                    if (!(Entry is XmlElement XDbNode))
                        continue;

                    if (!lstConnectionNodes.TryGetValue(XDbNode.Name, out var lstConn))
                    {
                        lstConn = new List<XmlElement>() { XDbNode };
                        lstConnectionNodes.Add(XDbNode.Name, lstConn);
                    }
                    else
                        lstConn.Add(XDbNode);
                }

                if (lstConnectionNodes.Count == 0)
                {
                    Parser.AddMessage(XNode, "No valid DB connection entries could be found in the infrastructure configuration.", LogLevels.Error);
                    return RetVal;
                }

                // parse the clustered db connection nodes
                foreach (var lstDbConn in lstConnectionNodes)
                {
                    Parser.EnterElement(lstDbConn.Key);
                    foreach (var XDbConn in lstDbConn.Value)
                    {
                        cDataHistoryConfigDbConnection DbConn = null;
                        switch (lstDbConn.Key)
                        {
                            case "SQL-Connection":
                                DbConn = new cDataHistoryConfigSqlConnection(XDbConn, Credentials, Parser);
                                break;
                            default:
                                Parser.AddMessage(XDbConn, $"The element '<{lstDbConn.Key}>' is not a valid DB connection element.", LogLevels.Error);
                                break;
                        }
                        if (DbConn != null)
                            RetVal.Add(DbConn.Name, DbConn);

                        Parser.SelectElementNext();
                    }
                    Parser.LeaveElement(lstDbConn.Key);
                }

            }
            catch (Exception E)
            {
                cLogManager.DefaultLogger.LogException(E);
            }
            finally
            {
                Parser.LeaveElement("DB-Connections");
                if (CM != null) LogMethodEnd(CM);
            }

            return RetVal;
        }

    }

    public class cDataHistoryConfigSqlConnection : cDataHistoryConfigDbConnection
    {
        public cCredential Credential { get; private set; } = null;

        public bool NativeAccount { get; private set; }

        public string Server { get; private set; }

        public string Instance { get; private set; }

        public string Database { get; private set; }

        public int Timeout { get; private set; } = -1;

        internal cDataHistoryConfigSqlConnection(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser) :
            base(XNode, Parser)
        {
            try
            {
                if (!IsValid)
                    return;

                IsValid = false;

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

                Instance = cXmlParser.GetStringFromXmlAttribute(XNode, "Instance");

                Database = cXmlParser.GetStringFromXmlAttribute(XNode, "Database");
                if (string.IsNullOrWhiteSpace(Server))
                {
                    Parser.AddInvalidAttribute(XNode, Name, "Database");
                    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, $"The credential attribute value '{strCredential}' of the element <{XNode.Name}> coud not be resolved.");
                    return;
                }
                Credential = _Cred;

                Timeout = cXmlParser.GetIntegerFromXmlAttribute(XNode, "Timeout", -1);
                if (Timeout < -1)
                    Timeout = -1;

                IsValid = true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

    }

}
