using C4IT.FASD.Base;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Basics.Helper
{
    internal class MenuItemDataProvider
    {
        private readonly cSupportCaseDataProvider _dataProvider;

        private const int defaultPinnedActionCount = 3; //search, notepad, copyTicketInformation

        public MenuItemDataProvider(cSupportCaseDataProvider dataProvider)
        {
            _dataProvider = dataProvider;
        }

        public List<cMenuDataBase> GetMenuItemData()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);

            List<cMenuDataBase> menuItemData = new List<cMenuDataBase>();

            try
            {
                foreach (var menuItemConfig in cF4SDCockpitXmlConfig.Instance.MenuItems.Values)
                {
                    cMenuDataBase menuItem = GetMenuItem(menuItemConfig);
                    if (menuItem is null)
                        continue;

                    int pinnedIndex = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.QuickActionsPinned.IndexOf(menuItemConfig.Name);
                    if (pinnedIndex > -1)
                        pinnedIndex += defaultPinnedActionCount;
                    menuItem.IconPositionIndex = pinnedIndex;
                    menuItemData.Add(menuItem);
                }
                FillMenuSection(menuItemData);
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return menuItemData;
        }

        private cMenuDataBase GetMenuItem(cFasdBaseConfigMenuItem menuItemConfig)
        {
            try
            {
                cMenuDataBase menuItem = null;
                switch (menuItemConfig)
                {
                    case cFasdQuickTip quickTip:
                        menuItem = GetQuickTipMenuItem(quickTip);
                        break;
                    case cFasdQuickAction quickAction:
                        menuItem = GetQuickActionMenuItem(quickAction);
                        break;
                    case cFasdMenuSection section:
                        menuItem = GetSectionMenuItem(section);
                        break;
                    case cCopyTemplate copyTemplate:
                        menuItem = GetCopyTemplateMenuItem(copyTemplate);
                        break;
                }

                if (menuItem != null)
                {
                    if (!cHealthCardDataHelper.IsUiVisible(menuItemConfig, _dataProvider.NamedParameterEntries))
                        menuItem.SetUiActionDisplayType(enumActionDisplayType.hidden);
                }
                return menuItem;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return null;
        }

        private cMenuDataBase GetCopyTemplateMenuItem(cCopyTemplate copyTemplate)
        {
            cMenuDataBase menuItem = new cMenuDataBase(copyTemplate);
            enumActionDisplayType displayType = HasRequiredInformationClasses(copyTemplate.InformationClasses)
                ? enumActionDisplayType.enabled : enumActionDisplayType.disabled;
            menuItem.SetUiActionDisplayType(displayType);
            return menuItem;
        }

        private cMenuDataBase GetSectionMenuItem(cFasdMenuSection section)
        {
            return new cMenuDataContainer(section);
        }

        private cMenuDataBase GetQuickActionMenuItem(cFasdQuickAction quickAction)
        {
            cMenuDataBase menuItem = new cMenuDataBase(quickAction);
            enumActionDisplayType displayType = HasAllRequirements(quickAction)
                ? enumActionDisplayType.enabled : enumActionDisplayType.disabled;
            menuItem.SetUiActionDisplayType(displayType);
            return menuItem;
        }

        private cMenuDataBase GetQuickTipMenuItem(cFasdQuickTip quickTip)
        {
            return new cMenuDataBase(quickTip);
            //TODO: Quick Actions einfügen
            //TODO: DisplayType prüfen + setzen
        }

        private bool HasRequiredInformationClasses(List<enumFasdInformationClass> required)
        {
            return !(required.Any(informationClass => _dataProvider?.Identities?.Any(identity => identity.Class == informationClass) == false));
        }


        private bool HasAllRequirements(cFasdQuickAction quickAction)
        {
            try
            {
                if (!HasRequiredInformationClasses(quickAction.InformationClasses))
                    return false;

                // if CheckNamedParamter the value of NamedParameter is set and if required equals one of the necessary values
                bool hasRequiredNamedParameter = quickAction.CheckNamedParameter is null
                    || (_dataProvider.NamedParameterEntries.TryGetValue(quickAction.CheckNamedParameter, out var namedParameterEntry)
                    && (quickAction.CheckNamedParameterValues is null || quickAction.CheckNamedParameterValues.Count == 0 || quickAction.CheckNamedParameterValues.Contains(namedParameterEntry.GetValue())));

                if (!hasRequiredNamedParameter)
                    return false;
                if (quickAction.CheckFilePath != null && !HasRequiredFilePath(quickAction.CheckFilePath))
                    return false;
                if (quickAction.CheckRegistryEntry != null && !HasRequiredRegistryEntry(quickAction.CheckRegistryEntry))
                    return false;

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

        private bool HasRequiredFilePath(string filePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(filePath))
                {
                    return true;
                }

                var specialFolders = Enum.GetValues(typeof(Environment.SpecialFolder)).Cast<Environment.SpecialFolder>();

                foreach (var specialFolder in specialFolders)
                {
                    var specialFolderName = "%" + specialFolder.ToString() + "%";
                    var specialFolderPath = Environment.GetFolderPath(specialFolder);
                    filePath = filePath.Replace(specialFolderName, specialFolderPath);
                }

                filePath = Environment.ExpandEnvironmentVariables(filePath);
                return File.Exists(filePath);
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return false;
        }

        private bool HasRequiredRegistryEntry(string registryEntry)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(registryEntry))
                {
                    return true;
                }
                var registryRootPath = registryEntry.Split('\\')[0];
                registryEntry = registryEntry.Replace(registryRootPath, "").Remove(0, 1);

                switch (registryRootPath)
                {
                    case "HKEY_LOCAL_MACHINE":
                    case "HKLM":
                        return Registry.LocalMachine.OpenSubKey(registryEntry) != null;
                    case "HKEY_CURRENT_USER":
                    case "HKCU":
                        return Registry.CurrentUser.OpenSubKey(registryEntry) != null;
                    default:
                        return false;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return false;
        }

        private void FillMenuSection(List<cMenuDataBase> menuItemData)
        {
            try
            {
                foreach (var section in menuItemData.OfType<cMenuDataContainer>())
                {
                    List<cMenuDataBase> subMenuData = menuItemData.Where(data =>
                        (data?.UiAction?.DisplayType != enumActionDisplayType.hidden) && (data?.MenuSections?.Contains(section.ContainerName) ?? false)).ToList();

                    section.SubMenuData = subMenuData;
                    if (section.UiAction is cSubMenuAction subMenuAction)
                        subMenuAction.SubMenuData = subMenuData;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

    }
}
