using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

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

using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Config;

using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi
{
    public enum enumM42AuthenticationMethod
    {
        passthrough = 0,
        basic,
        token,
        forms
    }

    public enum enumM42AuthenticationControl
    {
        auto = 0,
        never,
        always
    }

    public class cFasdCockpitConfig
    {
        public const string constRegPathConfig = @"Software\Consulting4IT GmbH\First Aid Service Desk\Cockpit";
        public const string constRegPathGlobal = "CockpitPreferences";

        [RegConfig]
        public string SelectedLanguage;

        [RegConfig]
        public enumAppColorMode DetailsPageColorMode = enumAppColorMode.LightMode;

        [RegConfig]
        public bool ShowSearchResultDetails = true;

        [RegConfig]
        public Int32 SlimPageZoom { get; private set; } = 100;

        [RegConfig]
        public Int32 DetailsPageZoom { get; private set; } = 100;

        [RegConfig]
        public string HighlightColorVisibility = "";

        [RegConfig]
        public string DetailsPageMaxGeometry = "";

        [RegConfig]
        public bool IsHistoryQuickActionSelectorVisible = false;

        [RegConfig]
        public bool IsCustomizableQuickActionSelectorVisible = true;

        [RegConfig]
        public bool IsNotepadVisibleDocked = false;

        [RegConfig]
        public bool IsNotepadVisibleUndocked = false;

        [RegConfig]
        public string LastDownloadPath = "";

        [RegConfig]
        public bool ShowRawHealthcardValues = false;

        [RegConfigSubItem]
        public cFasdCockpitConfigPhoneSupport PhoneSupport = new cFasdCockpitConfigPhoneSupport();

        [RegConfigSubItem]
        public cF4sdCockpitConfigM42 M42Config { get; set; } = new cF4sdCockpitConfigM42();

        [RegConfigSubItem(RegName: constRegPathGlobal)]
        public cF4sdGlobalConfigOld GlobalConfigOld = new cF4sdGlobalConfigOld();

        public cF4sdGlobalConfig Global = new cF4sdGlobalConfig(constRegPathConfig + @"\" + constRegPathGlobal);

        [RegConfigMetaInformation]
        private object ConfigMetaInformation = null;

        public static cFasdCockpitConfig Instance;

        public event EventHandler UiSettingsChanged;

        public cF4SDCockpitXmlConfig XmlConfig { get; private set; } = new cF4SDCockpitXmlConfig();

        public static bool IsAnalyticsActive = false;

        public static Guid SessionId = Guid.NewGuid();

        static cFasdCockpitConfig()
        {
            Instance = new cFasdCockpitConfig();
            Instance.Load();
            Instance.Save();
        }

        public void Load()
        {
            if (ConfigMetaInformation == null) { } // to avoid compiler warning

            cConfigRegistryHelper.Load(constRegPathConfig, this);
            Global.Load();


            // migrate old settings of SmallViewPosition
            if (cConfigRegistryHelper.IsPropertySetByUser("GlobalConfigOld\\SmallViewPosition", this))
                if (!cConfigRegistryHelper.IsPropertySetByUser("SmallViewAlignment", Global))
                {
                    var SmallViewAlignment = cF4sdGlobalConfig.ConvertPositionToHorizontalAlignment(GlobalConfigOld.SmallViewPosition, enumF4sdHorizontalAlignment.Right);
                    Global.SmallViewAlignment = SmallViewAlignment;
                    Global.Save("SmallViewAlignment");
                }

            // migrate old settings of FavouriteBarPosition
            if (cConfigRegistryHelper.IsPropertySetByUser("GlobalConfigOld\\FavouriteBarPosition", this))
                if (!cConfigRegistryHelper.IsPropertySetByUser("FavouriteBarAlignment", Global))
                {
                    var FavouriteBarAlignment = cF4sdGlobalConfig.ConvertPositionToHorizontalAlignment(GlobalConfigOld.FavouriteBarPosition, enumF4sdHorizontalAlignment.Right);
                    Global.FavouriteBarAlignment = FavouriteBarAlignment;
                    Global.Save("FavouriteBarAlignment");
                }
        }

        public void Save(string fullPropertyName = null)
        {
            cConfigRegistryHelper.Save(constRegPathConfig, this, fullPropertyName);
        }

        public void OnUiSettingsChanged()
        {
            UiSettingsChanged?.Invoke(this, EventArgs.Empty);
        }

        public void SetDetailsPageZoom(int zoom)
        {
            if (zoom == cFasdCockpitConfig.Instance.DetailsPageZoom)
                return;

            cFasdCockpitConfig.Instance.DetailsPageZoom = zoom;
            cFasdCockpitConfig.Instance.Save("DetailsPageZoom");
            OnUiSettingsChanged();
        }

        public void SetSlimPageZoom(int zoom)
        {
            if (zoom == cFasdCockpitConfig.Instance.SlimPageZoom)
                return;

            cFasdCockpitConfig.Instance.SlimPageZoom = zoom;
            cFasdCockpitConfig.Instance.Save("SlimPageZoom");
            OnUiSettingsChanged();
        }

        private void SetMenuItems()
        {
            try
            {
                if (cF4SDCockpitXmlConfig.Instance.MenuSectionConfig?.Sections?.MenuSections != null)
                {
                    foreach (var menuSection in cF4SDCockpitXmlConfig.Instance.MenuSectionConfig?.Sections?.MenuSections)
                    {
                        InsertMenuItem(menuSection.Key, menuSection.Value);
                    }
                }

                if (cF4SDCockpitXmlConfig.Instance.QuickActionConfig?.F4SDQuickActions?.QuickActions != null)
                {
                    foreach (var quickAction in cF4SDCockpitXmlConfig.Instance.QuickActionConfig?.F4SDQuickActions?.QuickActions)
                    {
                        InsertMenuItem(quickAction.Key, quickAction.Value);
                    }
                }

                if (cF4SDCockpitXmlConfig.Instance.QuickActionConfig?.F4SDQuickTips?.QuickTips != null)
                {
                    foreach (var quickTip in cF4SDCockpitXmlConfig.Instance.QuickActionConfig?.F4SDQuickTips?.QuickTips)
                    {
                        InsertMenuItem(quickTip.Key, quickTip.Value);
                    }
                }

                if (cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig?.CopyTemplates?.CopyTemplates != null)
                {
                    foreach (var copyTemplate in cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig?.CopyTemplates?.CopyTemplates)
                    {
                        InsertMenuItem(copyTemplate.Key, copyTemplate.Value);
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }

            void InsertMenuItem(string key, cFasdBaseConfigMenuItem menuItem)
            {
                if (cF4SDCockpitXmlConfig.Instance.MenuItems.ContainsKey(key))
                    LogEntry($"There was already a Menu Item with name '{key}'.", LogLevels.Warning);
                else
                    cF4SDCockpitXmlConfig.Instance.MenuItems.Add(key, menuItem);
            }
        }


        private void SetGlobalTranslations()
        {
            try
            {
                foreach (var healthcardTranslation in cF4SDCockpitXmlConfig.Instance.HealthCardConfig.Prerequisites.Translations)
                {
                    if (cF4SDCockpitXmlConfig.Instance.Translations.ContainsKey(healthcardTranslation.Key))
                        LogEntry($"There was allready an Global Translation with name '{healthcardTranslation.Key}'.", LogLevels.Warning);
                    else
                        cF4SDCockpitXmlConfig.Instance.Translations.Add(healthcardTranslation.Key, healthcardTranslation.Value);
                }

                foreach (var quickActionTranslation in cF4SDCockpitXmlConfig.Instance.QuickActionConfig.Translations)
                {
                    if (cF4SDCockpitXmlConfig.Instance.Translations.ContainsKey(quickActionTranslation.Key))
                        LogEntry($"There was allready an Global Translation with name '{quickActionTranslation.Key}'.", LogLevels.Warning);
                    else
                        cF4SDCockpitXmlConfig.Instance.Translations.Add(quickActionTranslation.Key, quickActionTranslation.Value);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        public async Task<bool> LoadConfigFilesAsync(cFasdCockpitCommunicationBase cockpitCommunication)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                cF4SDCockpitXmlConfig.Instance = new cF4SDCockpitXmlConfig();
                List<Task> tasks = new List<Task>();

                //Has to run first, because the other configs run a icon validation.
                cF4SDCockpitXmlConfig.Instance.HealthCardConfig = (cF4SDHealthCardConfig)await cockpitCommunication.GetConfiguration(enumFasdConfigurationType.healthCard);

                if (cF4SDCockpitXmlConfig.Instance.HealthCardConfig?.IsValid == true)
                    cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ParentNode = cF4SDCockpitXmlConfig.Instance;
                else
                {
                    cF4SDCockpitXmlConfig.Instance = null;
                    LogEntry("LoadConfigFilesAsync: Premature exit because no valid health card configuration exists.");
                    return false;
                }

                tasks.Add(Task.Run(async () => cF4SDCockpitXmlConfig.Instance.MenuSectionConfig = (cFasdMenuSectionConfiguration)await cockpitCommunication.GetConfiguration(enumFasdConfigurationType.menuSections)));
                tasks.Add(Task.Run(async () => cF4SDCockpitXmlConfig.Instance.QuickActionConfig = (cFasdQuickActionConfig)await cockpitCommunication.GetConfiguration(enumFasdConfigurationType.quickActions)));
                tasks.Add(Task.Run(async () => cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig = (cFasdCopyTemplateConfiguration)await cockpitCommunication.GetConfiguration(enumFasdConfigurationType.copyTemplates)));

                await Task.WhenAll(tasks);

                if (cF4SDCockpitXmlConfig.Instance.QuickActionConfig != null)
                {
                    cF4SDCockpitXmlConfig.Instance.QuickActionConfig.ParentNode = cF4SDCockpitXmlConfig.Instance;
                    SetGlobalTranslations();
                }

                SetMenuItems();

                if (cF4SDCockpitXmlConfig.Instance.MenuSectionConfig?.IsValid == true &&
                    cF4SDCockpitXmlConfig.Instance.QuickActionConfig?.IsValid == true &&
                    cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig?.IsValid == true
                    )
                    return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            LogEntry("LoadConfigFilesAsync: Invalid exit because at least one of the configuration files is not valid.");

            cF4SDCockpitXmlConfig.Instance = null;
            return false;
        }

        public async Task<bool> GetCockpitConfigurationAsync()
        {
            try
            {
                var _res = await cFasdCockpitCommunicationBase.Instance.GetCockpitConfiguration();
                if (!_res)
                    _res = await cFasdCockpitCommunicationBase.Instance.GetAgentApiAccessInfo();

                return _res;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return false;
        }

        public async Task<cCollectorStatusInfo> CheckCollectorStatusAsync()
        {
            try
            {
                var _res = await  cFasdCockpitCommunicationBase.Instance.CheckCollectorStatusAsync();
                if(_res != null)
                    return _res;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;
        }

        public bool HasM42Configuration()
        {
            try
            {
                return !string.IsNullOrWhiteSpace(cCockpitConfiguration.Instance?.m42ServerConfiguration?.Server);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return false;
        }

        public async Task InstantiateAnalyticsAsync(Guid SessionId)
        {
            try
            {
                IsAnalyticsActive = await cFasdCockpitCommunicationBase.Instance.IsAnalyticsModuleActive();
                if (IsAnalyticsActive)
                {
                    cF4sdUserInfo userInfo = null;
                    lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
                    {
                        userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo;
                    }
                    if (userInfo?.Id.Equals(Guid.Empty) is false)
                    {
                        await Task.Run(async () =>
                        {
                            try
                            {
                                var sessionParameter = new cF4SDUserSessionParameters() { SessionId = SessionId, UserId = userInfo.Id, SessionDate = DateTime.UtcNow };
                                var couldCreateUserSession = await cFasdCockpitCommunicationBase.Instance.CreateUserSession(sessionParameter);
                                if (couldCreateUserSession is false)
                                {
                                    LogEntry($"Could not create session '{SessionId}' for cockpit user '{userInfo.Id}'.", LogLevels.Warning);
                                    IsAnalyticsActive = false;
                                    return;
                                }

                                System.Timers.Timer sessionAliveTimer = new System.Timers.Timer(1000 * 60 * 10);
                                sessionAliveTimer.Start();
                                sessionAliveTimer.Elapsed += (async (sender, e) => { await cFasdCockpitCommunicationBase.Instance.KeepAliveSession(SessionId); });
                            }
                            catch (Exception E)
                            {
                                LogException(E);
                            }
                        });
                    }
                }
                else
                    LogEntry("Analytics - Analytics is not active.", LogLevels.Info);

            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        public async Task<bool> CheckAgentScriptAvailabilityAsync()
        {
            try
            {
                if (cCockpitConfiguration.Instance.agentApiConfiguration.OrganizationCode == null)
                    return false;

                var apiResult = await cFasdCockpitCommunicationBase.Instance.GetQuickActionsOfAgent();
                List<string> quickActionsToRemove = new List<string>();

                foreach (var quickActionKeyValuePair in cF4SDCockpitXmlConfig.Instance?.QuickActionConfig?.F4SDQuickActions.QuickActions)
                {
                    var quickAction = quickActionKeyValuePair.Value;
                    if (!(quickAction is cF4sdQuickActionRemote remoteQuickAction))
                        continue;

                    if (apiResult.Any(script => script.Id == remoteQuickAction.AgentScriptId))
                    {
                        var tempQuickAction = apiResult.First(script => script.Id == remoteQuickAction.AgentScriptId);

                        remoteQuickAction.ScriptName = tempQuickAction.Name;
                        remoteQuickAction.InformationClasses.Clear();

                        switch (tempQuickAction.Type)
                        {
                            case FasdCockpitBase.Models.enumAgentScriptType.computer:
                                remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.Computer);
                                break;
                            case FasdCockpitBase.Models.enumAgentScriptType.user:
                                remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.Computer);
                                remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.User);
                                break;
                            default:
                                remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.Unknown);
                                break;
                        }

                        continue;
                    }

                    if (remoteQuickAction.AgentScriptId == int.MinValue)
                    {
                        var tempQuickAction = apiResult.FirstOrDefault(script => script.Name == remoteQuickAction.ScriptName);
                        if (tempQuickAction != null)
                        {
                            remoteQuickAction.AgentScriptId = tempQuickAction.Id;

                            remoteQuickAction.InformationClasses.Clear();

                            switch (tempQuickAction.Type)
                            {
                                case FasdCockpitBase.Models.enumAgentScriptType.computer:
                                    remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.Computer);
                                    break;
                                case FasdCockpitBase.Models.enumAgentScriptType.user:
                                    remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.Computer);
                                    remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.User);
                                    break;
                                default:
                                    remoteQuickAction.InformationClasses.Add(enumFasdInformationClass.Unknown);
                                    break;
                            }

                            continue;
                        }
                    }

                    quickActionsToRemove.Add(quickActionKeyValuePair.Key);
                }

                foreach (var quickAction in quickActionsToRemove)
                {
                    cF4SDCockpitXmlConfig.Instance?.QuickActionConfig?.F4SDQuickActions.QuickActions.Remove(quickAction);
                    cF4SDCockpitXmlConfig.Instance?.MenuItems?.Remove(quickAction);
                }

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return false;
        }

        public async Task<bool> CheckServerQuickActionAvailabilityAsync()
        {
            try
            {

                var apiResult = await cFasdCockpitCommunicationBase.Instance.GetQuickActionsOfServer();
                List<string> quickActionsToRemove = new List<string>();

                foreach (var quickActionKeyValuePair in cF4SDCockpitXmlConfig.Instance?.QuickActionConfig?.F4SDQuickActions.QuickActions)
                {
                    var quickAction = quickActionKeyValuePair.Value;
                    if (!(quickAction is cF4sdQuickActionServer serverQuickAction))
                        continue;

                    if (!apiResult.Contains(quickAction.Name))
                    {
                        quickActionsToRemove.Add(quickActionKeyValuePair.Key);
                    }


                }

                foreach (var quickAction in quickActionsToRemove)
                {
                    cF4SDCockpitXmlConfig.Instance?.QuickActionConfig?.F4SDQuickActions.QuickActions.Remove(quickAction);
                    cF4SDCockpitXmlConfig.Instance?.MenuItems?.Remove(quickAction);
                }

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return false;
        }

    }


    public class cF4sdGlobalConfigOld
    {
        [RegConfig(ReadOnly: true)]
        public int SmallViewPosition { get; set; }

        [RegConfig(ReadOnly: true)]
        public int FavouriteBarPosition { get; set; }
    }

    public class cFasdCockpitConfigPhoneSupport
    {
        [RegConfig]
        public bool DisablePhoneSupport = false;

        [RegConfig]
        public bool PreferSwyxitNative = true;

        [RegConfig]
        public string PreferedTapiLine = null;

        [RegConfig]
        public bool UseTapi32Bit = false;

        [RegConfig]
        public bool SignalOutgoingCalls = false;

        [RegConfig]
        public string ExternalCallPrefix = null;

        [RegConfig]
        public bool ShowUnresolvedPhoneNumbers = false;

    }

    public class cF4sdCockpitConfigM42
    {
        [RegConfig]
        public enumM42AuthenticationMethod Method = enumM42AuthenticationMethod.passthrough;

        [RegConfig]
        public enumM42AuthenticationControl Control = enumM42AuthenticationControl.auto;

        [RegConfig]
        public string BasicUser = null;

        [RegConfig]
        public string BasicPassword = null;

        [RegConfig]
        public string ApiToken = null;

    }
}
