using Serilog; namespace Poe2Trade.Core; public class TradeLink { public string Id { get; set; } = ""; public string Url { get; set; } = ""; public string Name { get; set; } = ""; public string Label { get; set; } = ""; public bool Active { get; set; } = true; public LinkMode Mode { get; set; } = LinkMode.Live; public PostAction PostAction { get; set; } = PostAction.Stash; public string AddedAt { get; set; } = DateTime.UtcNow.ToString("o"); } public class LinkManager { private readonly Dictionary _links = new(); private readonly ConfigStore _store; public LinkManager(ConfigStore store) { _store = store; } public TradeLink AddLink(string url, string name = "", LinkMode? mode = null, PostAction? postAction = null) { url = StripLive(url); var id = ExtractId(url); var label = ExtractLabel(url); var savedLink = _store.Links.FirstOrDefault(l => l.Url == url); var resolvedMode = mode ?? savedLink?.Mode ?? LinkMode.Live; var link = new TradeLink { Id = id, Url = url, Name = name != "" ? name : savedLink?.Name ?? "", Label = label, Active = savedLink?.Active ?? true, Mode = resolvedMode, PostAction = postAction ?? savedLink?.PostAction ?? (resolvedMode == LinkMode.Scrap ? PostAction.Salvage : PostAction.Stash), AddedAt = DateTime.UtcNow.ToString("o") }; _links[id] = link; _store.AddLink(url, link.Name, link.Mode, link.PostAction); Log.Information("Trade link added: {Id} {Url} mode={Mode}", id, url, link.Mode); return link; } public void RemoveLink(string id) { if (_links.TryGetValue(id, out var link)) { _links.Remove(id); _store.RemoveLink(link.Url); } else { _store.RemoveLinkById(id); } Log.Information("Trade link removed: {Id}", id); } public TradeLink? ToggleLink(string id, bool active) { if (!_links.TryGetValue(id, out var link)) return null; link.Active = active; _store.UpdateLinkById(id, l => l.Active = active); Log.Information("Trade link {Action}: {Id}", active ? "activated" : "deactivated", id); return link; } public void UpdateName(string id, string name) { if (!_links.TryGetValue(id, out var link)) return; link.Name = name; _store.UpdateLinkById(id, l => l.Name = name); } public TradeLink? UpdateMode(string id, LinkMode mode) { if (!_links.TryGetValue(id, out var link)) return null; link.Mode = mode; _store.UpdateLinkById(id, l => l.Mode = mode); return link; } public TradeLink? UpdatePostAction(string id, PostAction postAction) { if (!_links.TryGetValue(id, out var link)) return null; link.PostAction = postAction; _store.UpdateLinkById(id, l => l.PostAction = postAction); return link; } public bool IsActive(string id) => _links.TryGetValue(id, out var link) && link.Active; public List GetLinks() => _links.Values.ToList(); public TradeLink? GetLink(string id) => _links.GetValueOrDefault(id); private static string StripLive(string url) => System.Text.RegularExpressions.Regex.Replace(url, @"/live/?$", ""); private static string ExtractId(string url) { var parts = url.Split('/'); return parts.Length > 0 ? parts[^1] : url; } private static string ExtractLabel(string url) { try { var uri = new Uri(url); var parts = uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries); var poe2Idx = Array.IndexOf(parts, "poe2"); if (poe2Idx >= 0 && parts.Length > poe2Idx + 2) { var league = Uri.UnescapeDataString(parts[poe2Idx + 1]); var searchId = parts[poe2Idx + 2]; return $"{league} / {searchId}"; } } catch { /* fallback */ } return url.Length > 60 ? url[..60] : url; } }