using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;

using Newtonsoft.Json;

using C4IT.Configuration;
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT.XML;

using static C4IT.Logging.cLogManager;
using static C4IT.Configuration.cConfigRegistryHelper;

namespace C4IT.DataHistoryProvider
{
    public class cDataHistoryConfigGolabalParameters : cFasdBaseConfig
    {
        public const string constFileNameF4sdConfig = "F4SD-Global-Configuration.xml";
        private const string constFileNameF4sdSchema = "F4SD-Global-Configuration.xsd";
        private const string constConfigRootElement = "F4SD-Global-Configuration";

        public cConfigHelperParameterList Parameters { get; private set; } = null;

        private cDataHistoryConfigInfrastructure InfrastructureConfig = null;

        internal cDataHistoryConfigGolabalParameters(cDataHistoryConfigInfrastructure configInfrastructure) :
            base(constFileNameF4sdConfig, constFileNameF4sdSchema, constConfigRootElement, true)
        {
            InfrastructureConfig = configInfrastructure;
        }

        public override bool InstantiateProperties(XmlElement RootElement, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

            try
            {
                Parameters = LoadParameters(RootElement, Parser );

                var _s = JsonConvert.SerializeObject(Parameters, Newtonsoft.Json.Formatting.Indented);

                this.IsValid = true;

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

            return false;

        }

        private cConfigHelperParameterList LoadParameters (XmlElement XRoot, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

            var _result = new cConfigHelperParameterList();

            try
            {
                var Items = XRoot.ChildNodes;
                foreach (var _node in Items)
                {
                    if (!(_node is XmlElement _item)) continue;

                    Parser.EnterElement(_item.Name);

                    try
                    {
                        var _attPolicy = _item.GetAttribute("Policy");
                        var _attValue = _item.GetAttribute("Value");

                        var _ElementCount = 0;
                        foreach (XmlNode _subNode in _item.ChildNodes)
                        {
                            if (_subNode is XmlElement)
                                _ElementCount++;
                        }

                        // check for special parameters
                        switch (_item.Name)
                        {
                            case "InformationClassSearchPriority":
                                var _val = getInformationClassSearchPriority(_item, Parser);
                                if (_val != null)
                                    _result.Items[_val.Name] = _val;
                                continue;
                            case "OpenActivitiesExternally":
                                var _openActivitiesEntry = getOpenActivitiesExternallyEntry(_item);
                                if (_openActivitiesEntry != null)
                                    _result.Items[_openActivitiesEntry.Name] = _openActivitiesEntry;

                                var _overrideValues = getOpenActivitiesExternallyOverrides(_item, Parser);
                                if (_overrideValues != null && _overrideValues.ValueList != null && _overrideValues.ValueList.Count > 0)
                                    _result.Items[_overrideValues.Name] = _overrideValues;
                                continue;
                            case "TicketProcessing":
                                var _ticketProcessingEntry = getTicketProcessingEntry(_item, Parser);
                                if (_ticketProcessingEntry != null)
                                    _result.Items[_ticketProcessingEntry.Name] = _ticketProcessingEntry;
                                continue;
                        }

                        if (_attPolicy != null && _attValue != null && _ElementCount == 0)
                        {
                            // we have a simple parameter
                            var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(_item, "Policy", enumConfigPolicy.Default);
                            var _value = cXmlParser.GetStringFromXmlAttribute(_item, "Value", String.Empty);

                            _result.Items[_item.Name] = new cConfigHelperParameterEntry()
                            {
                                Name = _item.Name,
                                Value = _value,
                                Policy = _policy.ToString(),
                            };
                        }
                        else if (string.IsNullOrEmpty(_attPolicy) && string.IsNullOrEmpty(_attValue) && _ElementCount > 0)
                        {
                            // we have a sublist
                            if (_result.SubItems == null)
                                _result.SubItems = new Dictionary<string, cConfigHelperParameterList>();
                            _result.SubItems[_item.Name] = LoadParameters(_item, Parser);
                        }
                        else
                        {
                            // we have an invalid entry
                            var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                        }
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                    finally
                    {
                        Parser.LeaveElement(_item.Name);
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

            return _result;
        }

        private cConfigHelperParameterEntry getInformationClassSearchPriority(XmlElement XNode, cXmlParser Parser)
        {

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

            try
            {
                var _xNodes = XNode.ChildNodes;

                var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);

                var _result = new List<string>();

                foreach (var _xNode in _xNodes)
                {
                    if (!(_xNode is XmlElement _item))
                        continue;

                    Parser.EnterElement(_item.Name);

                    try
                    {
                        if (_item.Name != "InformationClass")
                        {
                            // we have an invalid entry
                            var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}, should be <InformationClass/>";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                            continue;
                        }

                        var _InfoClass = cXmlParser.GetEnumFromAttribute<enumFasdInformationClass>(_item, "Type", enumFasdInformationClass.Unknown);
                        if (_InfoClass == enumFasdInformationClass.Unknown)
                        {
                            // we have an invalid type attribute
                            var _strType = cXmlParser.GetStringFromXmlAttribute(_item, "Type", String.Empty);
                            var _msg = $"Invalid type attribute value ({_strType}) in entry {_item.Name}";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                            continue;
                        }

                        var _strInfoClass = _InfoClass.ToString();
                        if (!_result.Contains(_strInfoClass))
                            _result.Add(_strInfoClass);
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                    finally
                    {
                        Parser.LeaveElement(_item.Name);
                    }
                }

                return new cConfigHelperParameterEntry()
                {
                    Name = XNode.Name,
                    ValueList = _result,
                    Policy = _policy.ToString()
                };
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

            return null;
        }

        private static cConfigHelperParameterEntry getTicketProcessingEntry(XmlElement XNode, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

            try
            {
                var _xNodes = XNode.SelectNodes("TicketTypeProcessing");

                var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
                var _value = cXmlParser.GetEnumFromAttribute<enumTicketProcessing>(XNode, "Value", enumTicketProcessing.Both);

                var _result = new List<string>();

                foreach (var _xNode in _xNodes)
                {
                    if (!(_xNode is XmlElement _item))
                        continue;

                    Parser.EnterElement(_item.Name);

                    try
                    {
                        var _ticketType = cXmlParser.GetEnumFromAttribute<enumTicketType>(_item, "Type", enumTicketType.Ticket);
                        var _processingValue = cXmlParser.GetEnumFromAttribute<enumTicketProcessing>(_item, "Value", enumTicketProcessing.Both);
                        _result.Add(_ticketType.ToString() + "=" + _processingValue.ToString());
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                    finally
                    {
                        Parser.LeaveElement(_item.Name);
                    }
                }

                var _retVal = new cConfigHelperParameterEntry()
                {
                    Name = XNode.Name,
                    ValueList = _result,
                    Policy = _policy.ToString()
                };

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

            return null;
        }


        private static cConfigHelperParameterEntry getOpenActivitiesExternallyEntry(XmlElement XNode)
        {
            var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
            var _value = cXmlParser.GetStringFromXmlAttribute(XNode, "Value", String.Empty);

            if (string.IsNullOrWhiteSpace(_value))
                return null;

            return new cConfigHelperParameterEntry()
            {
                Name = "OpenActivitiesExternally",
                Value = _value,
                Policy = _policy.ToString(),
            };
        }

        private cConfigHelperParameterEntry getOpenActivitiesExternallyOverrides(XmlElement XNode, cXmlParser Parser)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

            try
            {
                var _xNodes = XNode.ChildNodes;
                var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
                var _result = new List<string>();

                foreach (var _xNode in _xNodes)
                {
                    if (!(_xNode is XmlElement _item))
                        continue;

                    Parser.EnterElement(_item.Name);

                    try
                    {
                        if (_item.Name != "OpenActivityOverride")
                        {
                            var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}, should be <OpenActivityOverride/>";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                            continue;
                        }

                        var activityType = cXmlParser.GetStringFromXmlAttribute(_item, "ActivityType", String.Empty)?.Trim();
                        if (string.IsNullOrWhiteSpace(activityType))
                        {
                            var _msg = $"Missing ActivityType attribute value in entry {_item.Name}";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                            continue;
                        }

                        var valueText = cXmlParser.GetStringFromXmlAttribute(_item, "Value", String.Empty)?.Trim();
                        if (string.IsNullOrWhiteSpace(valueText))
                        {
                            var _msg = $"Missing Value attribute value in entry {_item.Name} ({activityType})";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                            continue;
                        }

                        var normalizedValue = valueText.ToLowerInvariant();
                        bool? parsedValue = null;
                        switch (normalizedValue)
                        {
                            case "true":
                            case "1":
                            case "yes":
                                parsedValue = true;
                                break;
                            case "false":
                            case "0":
                            case "no":
                                parsedValue = false;
                                break;
                        }

                        if (!parsedValue.HasValue)
                        {
                            var _msg = $"Invalid Value attribute value ({valueText}) in entry {_item.Name} ({activityType})";
                            Parser.AddMessage(_item, _msg, LogLevels.Warning);
                            LogEntry(_msg, LogLevels.Warning);
                            continue;
                        }

                        _result.Add($"{activityType}={(parsedValue.Value ? "true" : "false")}");
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                    finally
                    {
                        Parser.LeaveElement(_item.Name);
                    }
                }

                return new cConfigHelperParameterEntry()
                {
                    Name = "OpenActivitiesExternallyOverrides",
                    ValueList = _result,
                    Policy = _policy.ToString()
                };
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

            return null;
        }

        public override bool DoXmlUpdates(XmlElement XmlRoot, bool withM42Config = false, bool withIntuneConfig = false, bool withMobileDeviceConfig = false, bool withCitrixConfig = false)
        {
            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

            var RetVal = false;
            try
            {
                RetVal |= DoXmlInsertElement(XmlRoot
                     , ""
                     , "ShouldSkipSlimView"
                     , "<ShouldSkipSlimView Policy=\"Default\" Value=\"false\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , ""
                     , "SmallViewAlignment"
                     , "<SmallViewAlignment Policy=\"Default\" Value=\"Right\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , ""
                     , "FavouriteBarAlignment"
                     , "<FavouriteBarAlignment Policy=\"Default\" Value=\"Right\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , ""
                     , "InformationClassSearchPriority"
                     , "<InformationClassSearchPriority Policy=\"Default\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , "InformationClassSearchPriority"
                     , "InformationClass[@Type='User']"
                     , "<InformationClass Type=\"User\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , "InformationClassSearchPriority"
                     , "InformationClass[@Type='Computer']"
                     , "<InformationClass Type=\"Computer\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , "InformationClassSearchPriority"
                     , "InformationClass[@Type='VirtualSession']"
                     , "<InformationClass Type=\"VirtualSession\" />"
                     );

                RetVal |= DoXmlInsertElement(XmlRoot
                     , "InformationClassSearchPriority"
                     , "InformationClass[@Type='Ticket']"
                     , "<InformationClass Type=\"Ticket\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , ""
                     , "TicketConfiguration"
                     , "<TicketConfiguration />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "NotesMandatory"
                     , "<NotesMandatory Policy=\"Hidden\" Value=\"false\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "UseSimplifiedCaseCompletionDialog"
                     , "<UseSimplifiedCaseCompletionDialog Policy=\"Mandatory\" Value=\"false\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "SimplifiedCaseCompletionTicketOpenMode"
                     , $"<SimplifiedCaseCompletionTicketOpenMode Policy=\"Default\" Value=\"{enumTicketExternalOpenMode.Preview}\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "ShowOverview"
                     , "<ShowOverview Policy=\"Hidden\" Value=\"true\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "TicketProcessing"
                     , "<TicketProcessing Policy=\"Mandatory\" Value=\"both\"><TicketTypeProcessing Type=\"Ticket\" Value=\"intern\" /><TicketTypeProcessing Type=\"UnclassifiedTicket\" Value=\"intern\" /><TicketTypeProcessing Type=\"Incident\" Value=\"intern\" /></TicketProcessing>"
                     );
                RetVal |= DoXmlRemoveElement(XmlRoot
                     , "TicketConfiguration"
                     , "OpenActivitiesExternally"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "OverviewPollingPersonal"
                     , $"<OverviewPollingPersonal Policy=\"Hidden\" Value=\"{cF4sdTicketConfig.DefaultOverviewPollingPersonal}\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "OverviewPollingRole"
                     , $"<OverviewPollingRole Policy=\"Hidden\" Value=\"{cF4sdTicketConfig.DefaultOverviewPollingRole}\" />"
                     );
#pragma warning disable CS0618 // Type or member is obsolete
                var oldShowDocumentCaseDialog = InfrastructureConfig?.M42Wpm?.ShowDocumentCaseDialog ?? enumShowDocumentCaseDialog.ifRequired;
                var oldDisableAutomaticTimeTracking = InfrastructureConfig?.M42Wpm?.DisableAutomaticTimeTracking ?? false;
#pragma warning restore CS0618 // Type or member is obsolete
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "CompletitionPolicy"
                     , $"<CompletitionPolicy Policy=\"Hidden\" Value=\"{oldShowDocumentCaseDialog.ToString()}\" />"
                     );
                RetVal |= DoXmlInsertElement(XmlRoot
                     , "TicketConfiguration"
                     , "DisableAutomaticTimeTracking"
                     , $"<DisableAutomaticTimeTracking Policy=\"Mandatory\" Value=\"{oldDisableAutomaticTimeTracking.ToString().ToLowerInvariant()}\" />"
                     );

                if(withIntuneConfig)
                {
                    RetVal |= DoXmlInsertElement(XmlRoot
                        , ""
                        , "IntuneConfiguration"
                        , "<IntuneConfiguration />"
                        );

                    RetVal |= DoXmlInsertElement(XmlRoot
                         , "IntuneConfiguration"
                         , "TAPLifeTimeInMinutes"
                         , $"<TAPLifeTimeInMinutes Policy=\"Default\" Value=\"{cF4sdIntuneConfig.DefaultTAPLifeTimeInMinutes}\" />"
                     );

                    RetVal |= DoXmlInsertElement(XmlRoot
                         , "IntuneConfiguration"
                         , "TAPIsUsableOnce"
                         , $"<TAPIsUsableOnce Policy=\"Default\" Value=\"{cF4sdIntuneConfig.DefaultTAPIsUsableOnce}\" />"
                     );

                }
            }

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

            return RetVal;
        }

    }


}
