using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using C4IT.MultiLanguage;
using FasdDesktopUi.Basics;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services;
using FasdDesktopUi.Basics.Services.Models;
using FasdDesktopUi.Basics.Services.RelationService;
using FasdDesktopUi.Basics.Services.SupportCaseSearchService;
using FasdDesktopUi.Basics.UiActions;
using FasdDesktopUi.Basics.UserControls;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using static C4IT.Logging.cLogManager;
using static FasdDesktopUi.Basics.UserControls.TicketOverview;

namespace FasdDesktopUi.Pages.SearchPage
{
    public partial class SearchPageView : Window, ISearchUiProvider
    {
        private static SearchPageView _instance = null;
        private const int WM_NCHITTEST = 0x0084;
        private const int HTTRANSPARENT = -1;
        public static SearchPageView Instance
        {
            get
            {
                return _instance ?? (_instance = new SearchPageView());
            }
        }

        private cF4sdPipeServer _pipeServer;
        private cHotKeyManager _hotKeyManager;

        private CancellationTokenSource _searchCancellationTokenSource = new CancellationTokenSource();

        private bool _isActivating = false;

        private cF4sdApiSearchResultRelation preSelectedRelation = null;
        private bool _renderTicketOverviewUserNames = false;
        private readonly HashSet<cSearchHistorySearchResultEntry> _ticketOverviewHistoryEntries = new HashSet<cSearchHistorySearchResultEntry>();
        private const string DemoTicketHasDetailsInfoKey = "Demo.HasTicketDetails";
        // Event zum auslösen wenn Toggle geändert wird
        public event EventHandler<bool> FilterToggleCheckedChanged;

        // Aktueller Zustand der Checkbox
        public bool IsFilterChecked => FilterCheckbox.IsChecked == true;

        public SupportCaseSearchService SearchService { get; } = new SupportCaseSearchService(new RelationService());

        private SearchPageView()
        {
            try
            {
                InitializeComponent();
                Visibility = Visibility.Visible;
                _instance = this;

                // FilterToggleCheckBox-Events registrieren
                FilterCheckbox.Checked += (s, e) => FilterToggleCheckedChanged?.Invoke(this, true);
                FilterCheckbox.Unchecked += (s, e) => FilterToggleCheckedChanged?.Invoke(this, false);

                Loaded += (s, e) =>
                {
                    Hide();
                    SearchBarUc.ActivateManualSearch();
                };

                AddCustomEventHandlers();

                UiSettingsChanged(null, null);

                if (TicketOverviewUpdateService.Instance != null)
                {
                    TicketOverviewUpdateService.Instance.Start();
                    TicketOverviewUpdateService.Instance.OverviewCountsChanged += TicketOverviewUpdateService_OverviewCountsChanged;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void SetSearchResultVisibility(bool isVisible)
        {
            SearchResultBorder.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed;
            BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed;
        }

        public void SetSearchHistoryVisibility(bool isVisible)
        {
            SearchHistoryBorder.Visibility = isVisible && !SearchHistory.IsEmpty() ? Visibility.Visible : Visibility.Collapsed;
            BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed;
        }

        private bool CheckTicketOverviewAvailability()
        {
            if (cFasdCockpitCommunicationBase.Instance.IsDemo())
                return true;
            return false;
        }

        private void SetTicketOverviewVisibility(bool isVisible)
        {
            var b = isVisible;
            if (!CheckTicketOverviewAvailability())
                b = false;

            BodyStack_TicketOverview.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
            TicketOverviewBorder.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
            FilterCheckbox.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
            RoleLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
            OwnTicketsLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
            TicketOverviewLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed;
        }

        public void ShowLoadingTextItem(string itemText)
        {
            SetSearchHistoryVisibility(false);
            ResultMenu.ShowLoadingTextItem(itemText);
        }

        public void ShowTicketOverviewPane()
        {
            Dispatcher.Invoke(() =>
            {
                bool overviewAlreadyVisible = TicketOverviewBorder.Visibility == Visibility.Visible;

                SetTicketOverviewVisibility(true);

                if (!overviewAlreadyVisible)
                {
                    SetSearchResultVisibility(false);
                    SetSearchHistoryVisibility(false);
                    TicketOverviewUc?.ResetSelection();
                }
                TicketOverviewUc?.RefreshHighlightState(IsFilterChecked);

                var app = Application.Current as FasdDesktopUi.App;
                app?.ClearTicketOverviewTrayNotification();
            });
        }

        internal void CloseTicketOverviewResults()
        {
            _renderTicketOverviewUserNames = false;
            ResultMenu.ShowSearchResults(new cFilteredResults(), null, this);
            ResultMenu.SetHeaderText(string.Empty);
            SetSearchResultVisibility(false);
            SetTicketOverviewVisibility(true);
        }

        public void ShowSearchRelations(cSearchHistorySearchResultEntry searchHistoryEntry, IRelationService relationService, ISearchUiProvider searchUiProvider)
        {
            try
            {
                _renderTicketOverviewUserNames = searchHistoryEntry != null && _ticketOverviewHistoryEntries.Contains(searchHistoryEntry);
                Dispatcher.Invoke(() => ResultMenu.SetHeaderText(searchHistoryEntry.HeaderText, hideDetailsCheckbox: _renderTicketOverviewUserNames));

                cSearchManager.ResolveRelations(searchHistoryEntry.Relations);

                ILookup<enumFasdInformationClass, cMenuDataBase> relationsLookup = searchHistoryEntry.Relations
                    .OrderBy(r => r.UsingLevel)
                    .ThenBy(r => r.LastUsed)
                    .ToLookup(GetInformationClass, r => GetMenuData(r, relationService));

                Dispatcher.Invoke(() =>
                {
                    ResultMenu.UpdateSearchRelations(relationsLookup);
                    ResultMenu.SetHeaderText(searchHistoryEntry.HeaderText, hideDetailsCheckbox: _renderTicketOverviewUserNames);
                });
            }
            catch (Exception ex)
            {
                LogException(ex);
            }

            enumFasdInformationClass GetInformationClass(cF4sdApiSearchResultRelation relation) => cF4sdIdentityEntry.GetFromSearchResult(relation.Type);

            cMenuDataBase GetMenuData(cF4sdApiSearchResultRelation relation, IRelationService trelationService)
            {
                try
                {
                    var requiredInformationClasses = new List<enumFasdInformationClass>() { cF4sdIdentityEntry.GetFromSearchResult(relation.Type) };
                    bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(requiredInformationClasses);
                    string disabledReason = null;

                    if (!isEnabled)
                    {
                        disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty;
                    }
                    else if (ShouldDisableTicketRelationForDemo(relation))
                    {
                        isEnabled = false;
                        disabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty;
                    }
                    string trailingText = null;
                    if (_renderTicketOverviewUserNames && relation.Infos != null && relation.Infos.TryGetValue("UserDisplayName", out var relationUserDisplayName))
                    {
                        trailingText = relationUserDisplayName;
                    }
                    string summaryText = null;
                    if (_renderTicketOverviewUserNames && relation.Infos != null && relation.Infos.TryGetValue("Summary", out var relationSummary))
                    {
                        summaryText = relationSummary;
                    }
                    return new cMenuDataSearchRelation(relation)
                    {
                        MenuText = relation.DisplayName,
                        SubMenuText = summaryText,
                        TrailingText = trailingText,
                        UiAction = new cUiProcessSearchRelationAction(searchHistoryEntry, relation, relationService, searchUiProvider)
                        {
                            DisplayType = isEnabled ? enumActionDisplayType.enabled : enumActionDisplayType.disabled,
                            Description = isEnabled ? string.Empty : disabledReason,
                            AlternativeDescription = isEnabled ? string.Empty : disabledReason
                        }
                    };
                }
                catch (Exception ex)
                {
                    LogException(ex);
                    // >>> Fallback NICHT null: einfacher, aktivierter Eintrag <<<
                    string fallbackTrailingText = null;
                    if (_renderTicketOverviewUserNames && relation.Infos != null && relation.Infos.TryGetValue("UserDisplayName", out var relationUserDisplayNameFallback))
                    {
                        fallbackTrailingText = relationUserDisplayNameFallback;
                    }
                    string fallbackSummaryText = null;
                    if (_renderTicketOverviewUserNames && relation.Infos != null && relation.Infos.TryGetValue("Summary", out var relationSummaryFallback))
                    {
                        fallbackSummaryText = relationSummaryFallback;
                    }
                    string fallbackDisabledReason = null;
                    bool fallbackIsEnabled = true;
                    try
                    {
                        var required = new List<enumFasdInformationClass> { cF4sdIdentityEntry.GetFromSearchResult(relation.Type) };
                        fallbackIsEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required);
                        if (!fallbackIsEnabled)
                        {
                            fallbackDisabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty;
                        }
                        else if (ShouldDisableTicketRelationForDemo(relation))
                        {
                            fallbackIsEnabled = false;
                            fallbackDisabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty;
                        }
                    }
                    catch
                    {
                        fallbackIsEnabled = true;
                        fallbackDisabledReason = string.Empty;
                    }
                    return new cMenuDataSearchRelation(relation)
                    {
                        MenuText = relation.DisplayName,
                        SubMenuText = fallbackSummaryText,
                        TrailingText = fallbackTrailingText,
                        UiAction = new cUiProcessSearchRelationAction(searchHistoryEntry, relation, relationService, searchUiProvider)
                        {
                            DisplayType = fallbackIsEnabled ? enumActionDisplayType.enabled : enumActionDisplayType.disabled,
                            Description = fallbackIsEnabled ? string.Empty : fallbackDisabledReason,
                            AlternativeDescription = fallbackIsEnabled ? string.Empty : fallbackDisabledReason
                        }
                    };
                }
            }
        }

        private void TriggeredSearch(string searchValue)
        {
            try
            {
                var visibleWindows = Application.Current.Windows.Cast<Window>().Where(window => window.IsVisible && (window is SearchPageView) == false).ToList();
                visibleWindows.ForEach(window => window.Visibility = Visibility.Hidden);
                SearchBarUc.SetSearchText(searchValue);
                Show();
                Activate();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void ShowExternalSearchInfo(string strInfo, cFasdApiSearchResultCollection resultEntry, enumF4sdSearchResultClass Class)
        {
            var filteredResults = new cFilteredResults(resultEntry) { AutoContinue = true };
            var _t = ShowExternalSearchInfoAsync(strInfo, filteredResults, Class);
        }

        private async Task ShowExternalSearchInfoAsync(string strInfo, cFilteredResults result, enumF4sdSearchResultClass Class)
        {
            try
            {
                await this.Dispatcher.InvokeAsync(async () =>
                {
                    try
                    {
                        await SearchBarUc.SetFixedSearchResultAsync(Class, strInfo, result);

                        if (result.AutoContinue && result.Results?.Count == 1)
                        {
                            ResultMenu.IndexOfSelectedResultItem = 0;
                            ResultMenu.SelectCurrentResultItem();
                        }

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

        private void ActivateManualSearch()
        {
            CancledSearchAction();
            SearchBarUc.ActivateManualSearch();
            Show();
            Activate();

            if (cSearchManager.Instance.HistoryList.Count > 0)
            {
                SearchHistory.ShowSearchHistory();
                SetSearchHistoryVisibility(true);
            }
            else
                SetSearchHistoryVisibility(false);
        }

        public void PhoneCallSearch(cPhoneSearchParameters searchInfo)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var _h = Task.Run(async () =>
                {

                    try
                    {
                        var _result = await cFasdCockpitCommunicationBase.Instance.GetPhoneSearchResults(searchInfo);
                        if (_result != null && _result.Count > 0 || cFasdCockpitConfig.Instance?.PhoneSupport?.ShowUnresolvedPhoneNumbers is true)
                        {
                            string strTxt;
                            if (string.IsNullOrEmpty(searchInfo.name))
                                strTxt = searchInfo.phone;
                            else
                                strTxt = $"{searchInfo.name} ({searchInfo.phone})";
                            var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.Phonecall.Info"), strTxt);
                            ShowExternalSearchInfo(strInfo, _result, enumF4sdSearchResultClass.Phone);
                        }
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                });
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

        }

        private void ComputerDomainSearch(cComputerDomainSearchParameters searchInfo)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var _h = Task.Run(async () =>
                {

                    try
                    {
                        var _result = await cFasdCockpitCommunicationBase.Instance.GetComputerSearchResults(searchInfo.name, searchInfo.domain);
                        var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.ComputerSearch.Info"), searchInfo.name);
                        ShowExternalSearchInfo(strInfo, _result, enumF4sdSearchResultClass.Computer);

                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                });
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

        }

        private void UserSidSearch(cUserSidSearchParameters searchInfo)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var _h = Task.Run(async () =>
                {
                    try
                    {
                        var lstSids = searchInfo.sids.Split(',').Select((v) => v.Trim()).ToList();
                        var _result = await cFasdCockpitCommunicationBase.Instance.GetUserSearchResults(searchInfo.name, lstSids);
                        var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.UserSearch.Info"), searchInfo.name);
                        ShowExternalSearchInfo(strInfo, _result, enumF4sdSearchResultClass.User);
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                });
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

        }

        private void TicketSearch(cTicketSearchParameters searchInfo)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (!Guid.TryParse(searchInfo.ticketId, out var _ticketId))
                    return;

                var _h = Task.Run(async () =>
                {
                    try
                    {
                        var lstSids = searchInfo.sids?.Split(',').Select((v) => v.Trim()).ToList();
                        var _result = await cFasdCockpitCommunicationBase.Instance.GetUserSearchResults(searchInfo.userName, lstSids);

                        if (_result is null || _result.Count == 0 || _result.First().Value.Count == 0)
                        {
                            LogEntry($"No corresponding user could be found for ticket '{searchInfo.ticketName}'", LogLevels.Warning);
                            return;
                        }

                        var UserId = _result.Values.First().First().id;
                        var _ticketRelation = new cF4sdApiSearchResultRelation()
                        {
                            Type = enumF4sdSearchResultClass.Ticket,
                            DisplayName = searchInfo.ticketName,
                            id = _ticketId,
                            Status = enumF4sdSearchResultStatus.Active,
                            Identities = new cF4sdIdentityList
                            {
                                { new cF4sdIdentityEntry()
                                    {
                                        Class = enumFasdInformationClass.User,
                                        Id = UserId
                                    }
                                },
                                { new cF4sdIdentityEntry()
                                    {
                                        Class = enumFasdInformationClass.Ticket,
                                        Id = _ticketId
                                    }
                                },
                            }
                        };

                        var filteredResults = new cFilteredResults(_result) { AutoContinue = true, PreSelectedRelation = _ticketRelation };

                        var strInfo = string.Format(cMultiLanguageSupport.GetItem("Searchbar.TicketSearch.Info"), searchInfo.ticketName);
                        var _t = ShowExternalSearchInfoAsync(strInfo, filteredResults, enumF4sdSearchResultClass.Ticket);
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                });
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

        }

        private void PipeServer_PipeMessage(string reply)
        {
            try
            {
                var type = reply;
                if (type.Contains(':'))
                    type = reply.Substring(0, Math.Max(reply.IndexOf(':'), 0));
                type = type.ToLowerInvariant();

                if (string.IsNullOrWhiteSpace(type))
                {
                    LogEntry("No valid pipe reply", LogLevels.Warning);
                    return;
                }

                if (type == "hello")
                    return;

                if (DefaultLogger.IsDebug)
                {
                    var _msg = new List<string>() { "pipe message received:", reply };
                    DefaultLogger.LogList(LogLevels.Debug, _msg);
                }

                if (cConnectionStatusHelper.Instance?.ApiConnectionStatus is cConnectionStatusHelper.enumOnlineStatus.offline)
                    return;

                var value = reply.Remove(0, type.Length).TrimStart(':');

                switch (type)
                {
                    case "search":
                        try
                        {
                            Dispatcher.Invoke(() => TriggeredSearch(value));
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                        break;
                    case "phonesearch":
                        try
                        {
                            var searchInfo = JsonConvert.DeserializeObject<cPhoneSearchParameters>(value);
                            PhoneCallSearch(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                        break;
                    case "computerdomainsearch":
                        try
                        {
                            var searchInfo = JsonConvert.DeserializeObject<cComputerDomainSearchParameters>(value);
                            ComputerDomainSearch(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                        break;
                    case "usersidsearch":
                        try
                        {
                            var searchInfo = JsonConvert.DeserializeObject<cUserSidSearchParameters>(value);
                            UserSidSearch(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                        break;
                    case "ticketsearch":
                        try
                        {
                            var searchInfo = JsonConvert.DeserializeObject<cTicketSearchParameters>(value);
                            TicketSearch(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                        break;
                    default:
                        break;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);

            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                _pipeServer = new cF4sdPipeServer();
                _pipeServer.PipeMessage += PipeServer_PipeMessage;
                _pipeServer.Listen(App.PipeName, MaxSize: 4096, LowerIntegrity: true);
                LogEntry($"Start listening on named pipe '{App.PipeName}'...", LogLevels.Debug);

                IntPtr handle = new WindowInteropHelper(this).Handle;
                var hwndSource = HwndSource.FromHwnd(handle);
                hwndSource.AddHook(SearchViewWindowProc);
                hwndSource.AddHook(new HwndSourceHook(cUtility.WindowProc));

                var hotKeyDefinitions = new List<cHotKeyManager.cHotKeyDefinition>
                {
                    new cHotKeyManager.cHotKeyDefinition { Id = 1, Modifier = new List<ModifierKeys> { ModifierKeys.Control }, Key = Key.F3, HotKeyAction = HotKeyManager_ActivateSearch },
                    new cHotKeyManager.cHotKeyDefinition { Id = 2, Modifier = new List<ModifierKeys> { ModifierKeys.Control, ModifierKeys.Alt }, Key = Key.F3, HotKeyAction = HotKeyManager_CopyAndSearch }
                };

#if isDemo
                if (cFasdCockpitCommunicationBase.Instance?.IsDemo() == true)
                {
                    hotKeyDefinitions.Add(new cHotKeyManager.cHotKeyDefinition
                    {
                        Id = 3,
                        Modifier = new List<ModifierKeys> { ModifierKeys.Control, ModifierKeys.Alt },
                        Key = Key.T,
                        HotKeyAction = () => TicketOverviewUpdateService.Instance.SimulateDemoTicket()
                    });
                }
#endif

                _hotKeyManager = new cHotKeyManager(handle, hotKeyDefinitions);
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        public void ActivateSearchView()
        {
            if (_isActivating)
                return;

            _isActivating = true;

            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {


                bool doShow = true;

                if (doShow)
                {
                    ActivateManualSearch();
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                _isActivating = false;
                LogMethodEnd(CM);
            }
        }

        private void HotKeyManager_ActivateSearch()
        {
            if (!IsVisible)
                ActivateSearchView();
        }

        public void BringToFrontPreserveState()
        {
            Dispatcher.Invoke(() =>
            {
                if (!IsVisible)
                    Show();

                if (WindowState == WindowState.Minimized)
                    WindowState = WindowState.Normal;

                Activate();
                Topmost = true;
                Topmost = false;
                Focus();
            });
        }

        private async void HotKeyManager_CopyAndSearch()
        {
            try
            {
                bool isHotKeyDown = true;
                while (isHotKeyDown)
                {
                    isHotKeyDown = _hotKeyManager.IsKeyDown(cHotKeyManager.VirtualKeyStates.VK_F3) || _hotKeyManager.IsKeyDown(cHotKeyManager.VirtualKeyStates.VK_CONTROL) || _hotKeyManager.IsKeyDown(cHotKeyManager.VirtualKeyStates.VK_MENU);
                    await Task.Delay(50);
                }

                cUtility.SendCtrlCToCurrentWindow();

                await Task.Delay(150);

                var copiedText = Clipboard.GetText();
                copiedText = cUtility.CleanPhoneString(copiedText);
                copiedText = copiedText.Trim().Substring(0, Math.Min(copiedText.Trim().Length, 75));

                ActivateSearchView();

                if (copiedText != null)
                {
                    await Dispatcher.BeginInvoke((Action)delegate
                    {
                        Activate();
                        SearchBarUc.SetSearchText(copiedText);
                    }, DispatcherPriority.Render);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }

        }

        protected override void OnClosed(EventArgs e)
        {
            try
            {
                if (TicketOverviewUpdateService.Instance != null)
                    TicketOverviewUpdateService.Instance.OverviewCountsChanged -= TicketOverviewUpdateService_OverviewCountsChanged;
                _pipeServer?.Dispose();
            }
            catch { }
            _pipeServer = null;

            _hotKeyManager?.UnRegisterHotKeys();
            RemoveHandler(TicketOverview.SelectionRequestedEvent,
                new TicketOverviewSelectionRequestedEventHandler(TicketOverview_SelectionRequested));
            base.OnClosed(e);
        }

        private void AddCustomEventHandlers()
        {
            AddHandler(cUiActionBase.UiActionClickedEvent, new cUiActionBase.UiActionEventHandlerDelegate(UiActionWasTriggered));
            SearchBarUc.CancledSearchAction = CancledSearchAction;
            AddHandler(TicketOverview.SelectionRequestedEvent,
    new TicketOverviewSelectionRequestedEventHandler(TicketOverview_SelectionRequested), true);
            cFasdCockpitConfig.Instance.UiSettingsChanged += UiSettingsChanged;

            SearchBarUc.SearchValueChanged += HandleSearchValueChanged;
            SearchService.RelationsFound += HandleRelationsFound;
        }

        private async void HandleSearchValueChanged(object sender, string searchValue)
        {
            const int minSearchLength = 2;

            try
            {
                _searchCancellationTokenSource?.Cancel();
                _searchCancellationTokenSource = new CancellationTokenSource();

                if (string.IsNullOrWhiteSpace(searchValue))
                {
                    SearchBarUc.SetSpinnerVisibility(Visibility.Hidden);
                    UpdateSearchResults(new cFilteredResults());
                    return;
                }

                if (searchValue.Length < minSearchLength)
                    return;

                SearchBarUc.SetSpinnerVisibility(Visibility.Visible);
                cFasdApiSearchResultCollection searchResults = await SupportCaseSearchService.GetSearchResultsAsync(searchValue, _searchCancellationTokenSource.Token);
                SearchBarUc.SetSpinnerVisibility(Visibility.Hidden);
                UpdateSearchResults(new cFilteredResults(searchResults));
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e)
        {
            try
            {
                Dispatcher.Invoke(() =>
                {
                    var first = e.RelatedTo.FirstOrDefault();
                    var relationSearchResult = new cSearchHistorySearchResultEntry(first.DisplayName, first.DisplayName, e.RelatedTo.ToList(), e.StagedResultRelations.Relations.ToList(), this);
                    ShowSearchRelations(relationSearchResult, e.RelationService, this);

                    UpdatePendingInformationClasses(e.StagedResultRelations.PendingInformationClasses);
                });
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void TicketOverviewUpdateService_OverviewCountsChanged(object sender, TicketOverviewCountsChangedEventArgs e)
        {
            try
            {
                ApplyLatestCounts();
                var positiveChanges = e.Changes?.Where(change => change.Delta > 0).ToList();
                TicketOverviewUc?.SetHighlights(positiveChanges, IsFilterChecked);

                var app = Application.Current as FasdDesktopUi.App;

                if (positiveChanges == null || positiveChanges.Count == 0)
                {
                    app?.ClearTicketOverviewTrayNotification();
                    return;
                }

                var message = BuildNotificationMessage(positiveChanges);
                if (string.IsNullOrWhiteSpace(message))
                {
                    app?.ClearTicketOverviewTrayNotification();
                    return;
                }

                app?.ShowTicketOverviewTrayNotification(message);
                ShowTicketOverviewNotification(message);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void ApplyLatestCounts()
        {
            var service = TicketOverviewUpdateService.Instance;
            if (service == null)
                return;
            var counts = service.GetCountsForScope(IsFilterChecked);
            if (counts == null || counts.Count == 0)
                return;

            TicketOverviewUc?.UpdateCounts(counts, IsFilterChecked);
            TicketOverviewUc?.RefreshHighlightState(IsFilterChecked);
        }

        private string BuildNotificationMessage(IReadOnlyList<TileCountChange> changes)
        {
            if (changes == null || changes.Count == 0)
                return string.Empty;

            var aggregates = new List<(string RowKey, string ColumnKey, TileScope Scope, int Delta)>();
            var indexMap = new Dictionary<(string RowKey, string ColumnKey, TileScope Scope), int>();

            foreach (var change in changes)
            {
                if (!TryResolveTicketOverviewLabels(change.Key, out var rowKey, out var columnKey))
                    continue;

                var delta = change.NewCount - change.OldCount;
                if (delta == 0)
                    continue;

                var aggregateKey = (rowKey, columnKey, change.Scope);
                if (indexMap.TryGetValue(aggregateKey, out var aggregateIndex))
                {
                    var existing = aggregates[aggregateIndex];
                    aggregates[aggregateIndex] = (existing.RowKey, existing.ColumnKey, existing.Scope, existing.Delta + delta);
                }
                else
                {
                    indexMap[aggregateKey] = aggregates.Count;
                    aggregates.Add((rowKey, columnKey, change.Scope, delta));
                }
            }

            if (aggregates.Count == 0)
                return string.Empty;

            var pieces = new List<string>(aggregates.Count);
            foreach (var aggregate in aggregates)
            {
                if (aggregate.Delta == 0)
                    continue;

                var row = cMultiLanguageSupport.GetItem(aggregate.RowKey) ?? aggregate.RowKey;
                var column = cMultiLanguageSupport.GetItem(aggregate.ColumnKey) ?? aggregate.ColumnKey;
                var scopeRowLabel = GetScopeRowLabel(aggregate.Scope, aggregate.RowKey, row);
                var deltaText = aggregate.Delta >= 0 ? $"+{aggregate.Delta}" : aggregate.Delta.ToString();
                pieces.Add($"{scopeRowLabel} – {column} ({deltaText})");
            }

            return string.Join(Environment.NewLine, pieces);
        }

        private static bool TryResolveTicketOverviewLabels(string key, out string rowKey, out string columnKey)
        {
            rowKey = null;
            columnKey = null;

            if (string.IsNullOrWhiteSpace(key))
                return false;

            var normalized = key.ToLowerInvariant();

            if (normalized.StartsWith("tickets"))
                rowKey = "TicketOverview.Row.Heading.Tickets";
            else if (normalized.StartsWith("incident"))
                rowKey = "TicketOverview.Row.Heading.Incidents";
            else if (normalized.StartsWith("unassigned"))
                rowKey = "TicketOverview.Row.Heading.UnassignedTickets";
            else
                return false;

            columnKey = ResolveColumnTranslationKey(normalized);
            return columnKey != null;
        }

        private static string ResolveColumnTranslationKey(string normalizedKey)
        {
            if (normalizedKey.EndsWith("newinfo"))
                return "TicketOverview.Column.Heading.NewInfo";
            if (normalizedKey.EndsWith("critical"))
                return "TicketOverview.Column.Heading.Critical";
            if (normalizedKey.EndsWith("active"))
                return "TicketOverview.Column.Heading.Active";
            return "TicketOverview.Column.Heading.New";
        }

        private static string GetScopeRowLabel(TileScope scope, string rowKey, string rowLabel)
        {
            string suffix = null;
            if (string.Equals(rowKey, "TicketOverview.Row.Heading.Tickets", StringComparison.OrdinalIgnoreCase))
                suffix = "Tickets";
            else if (string.Equals(rowKey, "TicketOverview.Row.Heading.Incidents", StringComparison.OrdinalIgnoreCase))
                suffix = "Incidents";
            else if (string.Equals(rowKey, "TicketOverview.Row.Heading.UnassignedTickets", StringComparison.OrdinalIgnoreCase))
                suffix = "UnassignedTickets";

            var translationKey = scope == TileScope.Role
                ? $"TicketOverview.ScopeRow.Role.{suffix}"
                : $"TicketOverview.ScopeRow.Personal.{suffix}";

            return cMultiLanguageSupport.GetItem(translationKey) ?? rowLabel;
        }

        private IntPtr SearchViewWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_NCHITTEST)
            {
                if (!IsPointWithinInteractiveBounds(lParam))
                {
                    handled = true;
                    return new IntPtr(HTTRANSPARENT);
                }
            }

            return IntPtr.Zero;
        }

        private bool IsPointWithinInteractiveBounds(IntPtr lParam)
        {
            if (!IsLoaded || MainBorder == null || !MainBorder.IsLoaded)
                return true;

            if (MainBorder.ActualWidth <= 0 || MainBorder.ActualHeight <= 0)
                return true;

            var screenPoint = ExtractScreenPoint(lParam);
            var windowPoint = PointFromScreen(screenPoint);

            if (!(InputHitTest(windowPoint) is DependencyObject hitElement))
                return false;

            return IsDescendantOf(hitElement, MainBorder);
        }

        private static Point ExtractScreenPoint(IntPtr lParam)
        {
            int value = unchecked((int)(long)lParam);
            short x = (short)(value & 0xFFFF);
            short y = (short)((value >> 16) & 0xFFFF);
            return new Point(x, y);
        }

        private static bool IsDescendantOf(DependencyObject element, DependencyObject ancestor)
        {
            while (element != null)
            {
                if (element == ancestor)
                    return true;

                element = GetParent(element);
            }

            return false;
        }

        private static DependencyObject GetParent(DependencyObject current)
        {
            if (current == null)
                return null;

            if (current is Visual || current is System.Windows.Media.Media3D.Visual3D)
                return VisualTreeHelper.GetParent(current);

            if (current is System.Windows.ContentElement contentElement)
                return System.Windows.ContentOperations.GetParent(contentElement);

            return LogicalTreeHelper.GetParent(current);
        }

        private void ShowTicketOverviewNotification(string message)
        {
            if (string.IsNullOrWhiteSpace(message))
                return;

            try
            {
                var notificationTitle = cMultiLanguageSupport.GetItem("TicketOverview.Notification.Title") ?? "Ticketübersicht";
                var app = Application.Current as App;
                app?.notifyIcon?.ShowBalloonTip(3000, notificationTitle, message, System.Windows.Forms.ToolTipIcon.Info);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }
        private async void TicketOverview_SelectionRequested(object sender, TicketOverviewSelectionRequestedEventArgs e)
        {
            try
            {
                var app = Application.Current as FasdDesktopUi.App;
                app?.ClearTicketOverviewTrayNotification();

                _renderTicketOverviewUserNames = true;
                SetSearchHistoryVisibility(false);
                SetTicketOverviewVisibility(true);
                SetSearchResultVisibility(true);
                var header = BuildHeaderText(e.Key, e.UseRoleScope, e.Count);
                ResultMenu.SetHeaderText(header, hideDetailsCheckbox: true);

                ShowLoadingTextItem(cMultiLanguageSupport.GetItem("Searchbar.Loading.CaseData"));

                SetPendingInformationClasses(new HashSet<enumFasdInformationClass> { enumFasdInformationClass.Ticket });

                var relations = await LoadRelationsForTileAsync(e.Key, e.UseRoleScope, Math.Max(0, e.Count));
                Debug.WriteLine($"[TicketOverview] Relations loaded: {relations?.Count ?? 0}");
                var firstRelation = relations.FirstOrDefault();
                string displayText = header;
                if (firstRelation != null)
                {
                    string firstSummary = null;
                    if (firstRelation.Infos != null && firstRelation.Infos.TryGetValue("Summary", out var summaryValue))
                    {
                        firstSummary = summaryValue;
                    }

                    displayText = string.IsNullOrWhiteSpace(firstSummary)
                        ? $"{header} → {firstRelation.DisplayName}"
                        : $"{header} → {firstRelation.DisplayName} – {firstSummary}";
                }

                var entry = new cSearchHistorySearchResultEntry(
                    displayText,
                    header,
                    new List<cFasdApiSearchResultEntry>(),
                    relations,
                    this
                )
                { isSeen = true };
                _ticketOverviewHistoryEntries.Add(entry);

                var lookup = relations.ToLookup(
                    r => cF4sdIdentityEntry.GetFromSearchResult(r.Type),
                    r =>
                    {
                        var required = new List<enumFasdInformationClass> { cF4sdIdentityEntry.GetFromSearchResult(r.Type) };
                        bool isEnabled = cHealthCardDataHelper.HasAvailableHealthCard(required);
                        string disabledReason = null;
                        if (!isEnabled)
                        {
                            disabledReason = cMultiLanguageSupport.GetItem("Searchbar.NoValidHealthcard") ?? string.Empty;
                        }
                        else if (ShouldDisableTicketRelationForDemo(r))
                        {
                            isEnabled = false;
                            disabledReason = cMultiLanguageSupport.GetItem("Searchbar.Demo.NoTicketDetails") ?? string.Empty;
                        }
                        string trailingUser = null;
                        if (_renderTicketOverviewUserNames && r.Infos != null && r.Infos.TryGetValue("UserDisplayName", out var userDisplayName))
                        {
                            trailingUser = userDisplayName;
                        }
                        return (cMenuDataBase)new cMenuDataSearchRelation(r)
                        {
                            MenuText = r.DisplayName,
                            TrailingText = trailingUser,
                            UiAction = new cUiProcessSearchRelationAction(entry, r, null, this)
                            {
                                DisplayType = isEnabled ? enumActionDisplayType.enabled : enumActionDisplayType.disabled,
                                Description = isEnabled ? string.Empty : disabledReason,
                                AlternativeDescription = isEnabled ? string.Empty : disabledReason
                            }
                        };
                    }
                );
                ResultMenu.UpdateSearchRelations(lookup);
                ResultMenu.SetHeaderText(header, hideDetailsCheckbox: true);

                UpdatePendingInformationClasses(new HashSet<enumFasdInformationClass>());
            }
            catch (Exception ex)
            {
                LogException(ex);
                CancledSearchAction();
            }
            System.Diagnostics.Debug.WriteLine(
                $"[TicketOverview] Key={e.Key}, UseRoleScope={e.UseRoleScope}, Count={e.Count}");
        }
        private string BuildHeaderText(string key, bool useRoleScope, int? count = null)
        {
            string scopeKey = useRoleScope ? "Searchbar.Header.Scope.Role" : "Searchbar.Header.Scope.Personal";
            string entityKey = DetermineFallbackEntityKey(key);
            string filterKey = DetermineFallbackFilterKey(key);

            string scope = cMultiLanguageSupport.GetItem(scopeKey) ?? scopeKey;
            string entity = cMultiLanguageSupport.GetItem(entityKey) ?? entityKey;
            string filter = cMultiLanguageSupport.GetItem(filterKey) ?? filterKey;
            string template = cMultiLanguageSupport.GetItem("Searchbar.Header.Template") ?? "{0} - {1} ({2})";

            bool expectsCount = template.IndexOf("{3}", StringComparison.Ordinal) >= 0;
            try
            {
                if (expectsCount)
                {
                    int countValue = count ?? 0;
                    return string.Format(template, entity, filter, scope, countValue);
                }

                return string.Format(template, entity, filter, scope);
            }
            catch (FormatException)
            {
                return string.Format("{0} - {1} ({2})", entity, filter, scope);
            }
        }

        private string DetermineFallbackEntityKey(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                return "Searchbar.Header.Entity.Tickets";

            var keyLower = key.ToLowerInvariant();
            return keyLower.Contains("incident")
                ? "Searchbar.Header.Entity.Incidents"
                : "Searchbar.Header.Entity.Tickets";
        }

        private string DetermineFallbackFilterKey(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                return "Searchbar.Header.Filter.Overview";

            var keyLower = key.ToLowerInvariant();

            if (keyLower.Contains("newinfo"))
                return "Searchbar.Header.Filter.NewInfo";
            if (keyLower.Contains("new"))
                return "Searchbar.Header.Filter.New";
            if (keyLower.Contains("active"))
                return "Searchbar.Header.Filter.Active";
            if (keyLower.Contains("critical"))
                return "Searchbar.Header.Filter.Critical";
            if (keyLower.Contains("unassigned"))
                return "Searchbar.Header.Filter.Unassigned";
            if (keyLower.Contains("hold") || keyLower.Contains("onhold") || keyLower.Contains("wait"))
                return "Searchbar.Header.Filter.OnHold";
            if (keyLower.Contains("closed"))
                return "Searchbar.Header.Filter.Closed";

            return "Searchbar.Header.Filter.Overview";
        }

        private bool ShouldDisableTicketRelationForDemo(cF4sdApiSearchResultRelation relation)
        {
            if (relation == null)
                return false;

            var communication = cFasdCockpitCommunicationBase.Instance;
            if (communication?.IsDemo() != true)
                return false;

            if (relation.Type != enumF4sdSearchResultClass.Ticket)
                return false;

            if (relation.Infos == null)
                return false;

            if (!relation.Infos.TryGetValue(DemoTicketHasDetailsInfoKey, out var hasDetailsValue))
                return false;

            if (bool.TryParse(hasDetailsValue, out var hasDetails))
                return !hasDetails;

            return true;
        }

        private async Task<List<cF4sdApiSearchResultRelation>> LoadRelationsForTileAsync(string key, bool useRoleScope, int count)
        {
            var communication = cFasdCockpitCommunicationBase.Instance;
            if (communication == null)
                return new List<cF4sdApiSearchResultRelation>();
            try
            {
                var relations = await communication.GetTicketOverviewRelations(key, useRoleScope, Math.Max(0, count)).ConfigureAwait(false);
                var list = relations?.ToList() ?? new List<cF4sdApiSearchResultRelation>();

                if (TicketOverviewUpdateService.Instance != null)
                    foreach (var demoRelation in TicketOverviewUpdateService.Instance.GetDemoRelations(key, useRoleScope))
                    {
                        if (!list.Any(r => r.id == demoRelation.id))
                            list.Add(demoRelation);
                    }

                return list;
            }
            catch (Exception ex)
            {
                LogException(ex);
                return new List<cF4sdApiSearchResultRelation>();
            }
        }

        private void UpdateSearchResults(cFilteredResults filteredResults)
        {
            this.Dispatcher.Invoke(new Action(() =>
            {
                try
                {
                    _renderTicketOverviewUserNames = false;

                    if (filteredResults?.Results is null)
                    {
                        SetSearchResultVisibility(false);
                        SetTicketOverviewVisibility(true);
                        return;
                    }

                    string menuHeaderText = filteredResults?.PreSelectedRelation?.DisplayName;
                    ResultMenu.ShowSearchResults(filteredResults, menuHeaderText, this);
                    preSelectedRelation = filteredResults.PreSelectedRelation;

                    SetSearchResultVisibility(true);
                    SetTicketOverviewVisibility(false);
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }));
        }



        private void CancledSearchAction()
        {
            _renderTicketOverviewUserNames = false;
            SearchBarUc.Clear();
            ResultMenu.ShowSearchResults(new cFilteredResults(), null, this);
            SetSearchResultVisibility(false);
            SetSearchHistoryVisibility(false);
            SetTicketOverviewVisibility(true);
            Visibility = Visibility.Hidden;
        }

        private void SlimPageWindowStateBar_ClickedClose(object sender, RoutedEventArgs e)
        {
            CancledSearchAction();
        }

        private async void UiActionWasTriggered(object sender, UiActionEventArgs e)
        {
            try
            {
                if (e.UiAction == null)
                    return;

                Mouse.OverrideCursor = Cursors.Wait;

                switch (e.UiAction)
                {
                    case cUiProcessSearchResultAction searchResultAction:
                        searchResultAction.PreSelectedSearchRelation = preSelectedRelation;
                        break;
                    case cUiProcessSearchRelationAction _:
                    case cUiProcessSearchHistoryEntry _:
                        break;
                    default:
                        var _t = e.UiAction?.GetType().Name;
                        Debug.Assert(true, $"The UI action '{_t}' is not supported in detailed page");
                        CancledSearchAction();
                        return;
                }

                SetSearchResultVisibility(true);
                if (!await e.UiAction.RunUiActionAsync(sender, null, false, null))
                    CancledSearchAction();
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                    if (ResultMenu.IndexOfSelectedResultItem == int.MinValue)
                        ResultMenu.IndexOfSelectedResultItem = ResultMenu.GetSearchResultCount() - 1;
                    else
                        ResultMenu.IndexOfSelectedResultItem--;
                    break;
                case Key.Down:
                    if (ResultMenu.IndexOfSelectedResultItem == int.MinValue)
                        ResultMenu.IndexOfSelectedResultItem = 0;
                    else
                        ResultMenu.IndexOfSelectedResultItem++;
                    break;
                case Key.Enter:
                    ResultMenu.SelectCurrentResultItem();
                    e.Handled = true;
                    break;
                case Key.Escape:
                    CancledSearchAction();
                    break;
            }
        }

        private void UiSettingsChanged(object sender, EventArgs e)
        {
            try
            {
                var positionAlignement = cFasdCockpitConfig.Instance.Global.SmallViewAlignment;

                switch (positionAlignement)
                {
                    case enumF4sdHorizontalAlignment.Center:
                        Dispatcher.Invoke(() => MainBorder.HorizontalAlignment = HorizontalAlignment.Center);
                        break;
                    case enumF4sdHorizontalAlignment.Right:
                        Dispatcher.Invoke(() => MainBorder.HorizontalAlignment = HorizontalAlignment.Right);
                        break;
                    default:
                        Dispatcher.Invoke(() => MainBorder.HorizontalAlignment = HorizontalAlignment.Left);
                        break;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        public void SetPendingInformationClasses(HashSet<enumFasdInformationClass> informationClasses) => Dispatcher.Invoke(() => ResultMenu.SetPendingInformationClasses(informationClasses));

        public void UpdatePendingInformationClasses(HashSet<enumFasdInformationClass> informationClasses) => Dispatcher.Invoke(() => ResultMenu.UpdatePendingInformationClasses(informationClasses));
    }
}
