< Summary

Information
Class: Chronicis.Client.Services.WikiLinkAutocompleteService
Assembly: Chronicis.Client
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Client/Services/WikiLinkAutocompleteService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 93
Coverable lines: 93
Total lines: 171
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 56
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Position()100%210%
get_IsVisible()100%210%
get_Query()100%210%
get_IsExternalQuery()100%210%
get_ExternalSourceKey()100%210%
get_Suggestions()100%210%
get_SelectedIndex()100%210%
get_IsLoading()100%210%
.ctor(...)100%210%
ShowAsync()0%600240%
Hide()0%620%
SelectNext()0%2040%
SelectPrevious()0%2040%
SetSelectedIndex(...)0%4260%
GetSelectedSuggestion()0%4260%
TryParseExternalQuery(...)0%110100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Client/Services/WikiLinkAutocompleteService.cs

#LineLine coverage
 1namespace Chronicis.Client.Services;
 2
 3public class WikiLinkAutocompleteService : IWikiLinkAutocompleteService
 4{
 5    private readonly ILinkApiService _linkApiService;
 6    private readonly IExternalLinkApiService _externalLinkApiService;
 7    private readonly ILogger<WikiLinkAutocompleteService> _logger;
 8
 9    public event Action? OnShow;
 10    public event Action? OnHide;
 11    public event Action? OnSuggestionsUpdated;
 12
 013    public (double X, double Y) Position { get; private set; }
 014    public bool IsVisible { get; private set; }
 015    public string Query { get; private set; } = string.Empty;
 016    public bool IsExternalQuery { get; private set; }
 017    public string? ExternalSourceKey { get; private set; }
 018    public List<WikiLinkAutocompleteItem> Suggestions { get; private set; } = new();
 019    public int SelectedIndex { get; private set; }
 020    public bool IsLoading { get; private set; }
 21
 022    public WikiLinkAutocompleteService(
 023        ILinkApiService linkApiService,
 024        IExternalLinkApiService externalLinkApiService,
 025        ILogger<WikiLinkAutocompleteService> logger)
 26    {
 027        _linkApiService = linkApiService;
 028        _externalLinkApiService = externalLinkApiService;
 029        _logger = logger;
 030    }
 31
 32    public async Task ShowAsync(string query, double x, double y, Guid? worldId)
 33    {
 034        Position = (x, y);
 035        IsVisible = true;
 036        SelectedIndex = 0;
 37
 038        IsExternalQuery = TryParseExternalQuery(query, out var sourceKey, out var remainder);
 039        ExternalSourceKey = IsExternalQuery ? sourceKey : null;
 040        Query = IsExternalQuery ? remainder : query;
 41
 042        OnShow?.Invoke();
 43
 44        // For external queries: no minimum length (show categories)
 45        // For internal queries: require 3 characters minimum
 046        var minLength = IsExternalQuery ? 0 : 3;
 47
 048        if (Query.Length < minLength)
 49        {
 050            Suggestions = new();
 051            OnSuggestionsUpdated?.Invoke();
 052            return;
 53        }
 54
 055        IsLoading = true;
 056        OnSuggestionsUpdated?.Invoke();
 57
 58        try
 59        {
 060            if (IsExternalQuery)
 61            {
 062                var externalSuggestions = await _externalLinkApiService.GetSuggestionsAsync(
 063                    worldId ?? Guid.Empty,
 064                    ExternalSourceKey ?? string.Empty,
 065                    Query,
 066                    CancellationToken.None);
 67
 068                Suggestions = externalSuggestions
 069                    .Select(WikiLinkAutocompleteItem.FromExternal)
 070                    .ToList();
 71            }
 72            else
 73            {
 074                var internalSuggestions = await _linkApiService.GetSuggestionsAsync(
 075                    worldId ?? Guid.Empty,
 076                    Query);
 77
 078                Suggestions = internalSuggestions
 079                    .Select(WikiLinkAutocompleteItem.FromInternal)
 080                    .ToList();
 81            }
 082        }
 083        catch (Exception ex)
 84        {
 085            _logger.LogError(ex, "Error getting autocomplete suggestions for query: {Query}", query);
 086            Suggestions = new();
 087        }
 88        finally
 89        {
 090            IsLoading = false;
 091            OnSuggestionsUpdated?.Invoke();
 92        }
 093    }
 94
 95    public void Hide()
 96    {
 097        IsVisible = false;
 098        Suggestions = new();
 099        IsExternalQuery = false;
 0100        ExternalSourceKey = null;
 0101        Query = string.Empty;
 0102        SelectedIndex = 0;
 103
 0104        OnHide?.Invoke();
 0105    }
 106
 107    public void SelectNext()
 108    {
 0109        if (Suggestions.Any())
 110        {
 0111            SelectedIndex = (SelectedIndex + 1) % Suggestions.Count;
 0112            OnSuggestionsUpdated?.Invoke();
 113        }
 0114    }
 115
 116    public void SelectPrevious()
 117    {
 0118        if (Suggestions.Any())
 119        {
 0120            SelectedIndex = (SelectedIndex - 1 + Suggestions.Count) % Suggestions.Count;
 0121            OnSuggestionsUpdated?.Invoke();
 122        }
 0123    }
 124
 125    public void SetSelectedIndex(int index)
 126    {
 0127        if (index >= 0 && index < Suggestions.Count)
 128        {
 0129            SelectedIndex = index;
 0130            OnSuggestionsUpdated?.Invoke();
 131        }
 0132    }
 133
 134    public WikiLinkAutocompleteItem? GetSelectedSuggestion()
 135    {
 0136        if (Suggestions.Any() && SelectedIndex >= 0 && SelectedIndex < Suggestions.Count)
 137        {
 0138            return Suggestions[SelectedIndex];
 139        }
 0140        return null;
 141    }
 142
 143    private static bool TryParseExternalQuery(string query, out string sourceKey, out string remainder)
 144    {
 0145        sourceKey = string.Empty;
 0146        remainder = string.Empty;
 147
 0148        if (string.IsNullOrWhiteSpace(query))
 0149            return false;
 150
 0151        var slashIndex = query.IndexOf('/');
 0152        if (slashIndex < 0)
 153        {
 154            // No slash found - check if it could be a source key prefix
 0155            var lowerQuery = query.ToLowerInvariant();
 0156            if (lowerQuery.StartsWith("srd") ||
 0157                lowerQuery.StartsWith("open5e") ||
 0158                lowerQuery.StartsWith("ros"))
 159            {
 0160                sourceKey = lowerQuery;
 0161                remainder = string.Empty;
 0162                return true;
 163            }
 0164            return false;
 165        }
 166
 0167        sourceKey = query.Substring(0, slashIndex).ToLowerInvariant();
 0168        remainder = query.Substring(slashIndex + 1);
 0169        return true;
 170    }
 171}