using EchoHub.Core.Models; namespace EchoHub.Client.Commands; public record CommandResult(bool Handled, string? Message = null, bool IsError = false); public class CommandHandler { public event Func? OnSetStatus; public event Func? OnSetNick; public event Func? OnSetColor; public event Func? OnSetTheme; public event Func? OnSendFile; public event Func? OnOpenProfile; public event Func? OnOpenServers; public event Func? OnJoinChannel; public event Func? OnLeaveChannel; public event Func? OnSetTopic; public event Func? OnListUsers; public event Func? OnQuit; public event Func? OnHelp; public bool IsCommand(string input) => input.StartsWith('/'); public async Task HandleAsync(string input) { if (!IsCommand(input)) return new CommandResult(false); var parts = input[1..].Split(' ', 2, StringSplitOptions.TrimEntries); var command = parts[0].ToLowerInvariant(); var args = parts.Length > 1 ? parts[1] : string.Empty; return command switch { "status" => await HandleStatus(args), "nick" => await HandleNick(args), "color" => await HandleColor(args), "theme" => await HandleTheme(args), "send" => await HandleSend(args), "profile" => await HandleProfile(), "servers" => await HandleServers(), "join" => await HandleJoin(args), "leave" => await HandleLeave(), "topic" => await HandleTopic(args), "users" => await HandleUsers(), "quit" or "exit" => await HandleQuit(), "help" or "?" => await HandleHelp(), _ => new CommandResult(true, $"Unknown command: /{command}. Type /help for available commands.", IsError: true), }; } private async Task HandleStatus(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /status or /status ", IsError: true); var statusArg = args.ToLowerInvariant().Trim(); UserStatus? status = statusArg switch { "online" => UserStatus.Online, "away" => UserStatus.Away, "dnd" or "donotdisturb" => UserStatus.DoNotDisturb, "invisible" => UserStatus.Invisible, _ => null, }; if (status.HasValue) { if (OnSetStatus is not null) await OnSetStatus(status.Value, null); return new CommandResult(true, $"Status set to {status.Value}"); } // Treat as custom status message (keep current status) if (OnSetStatus is not null) await OnSetStatus(UserStatus.Online, args); return new CommandResult(true, $"Status message set: {args}"); } private async Task HandleNick(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /nick ", IsError: true); if (OnSetNick is not null) await OnSetNick(args.Trim()); return new CommandResult(true, $"Display name set to: {args.Trim()}"); } private async Task HandleColor(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /color (e.g., /color #FF5733)", IsError: true); var color = args.Trim(); if (!color.StartsWith('#')) color = "#" + color; if (color.Length != 7 || !IsValidHex(color[1..])) return new CommandResult(true, "Invalid color. Use hex format: #RRGGBB", IsError: true); if (OnSetColor is not null) await OnSetColor(color); return new CommandResult(true, $"Nickname color set to: {color}"); } private async Task HandleTheme(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /theme (Default, Dark, Light, Hacker, Solarized)", IsError: true); if (OnSetTheme is not null) await OnSetTheme(args.Trim()); return new CommandResult(true, $"Theme switched to: {args.Trim()}"); } private async Task HandleSend(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /send ", IsError: true); var target = args.Trim().Trim('"'); if (Uri.TryCreate(target, UriKind.Absolute, out var uri) && (uri.Scheme == "http" || uri.Scheme == "https")) { if (OnSendFile is not null) await OnSendFile(target); var fileName = Path.GetFileName(uri.LocalPath); if (string.IsNullOrWhiteSpace(fileName)) fileName = "download"; return new CommandResult(true, $"Downloading & uploading: {fileName}..."); } if (!File.Exists(target)) return new CommandResult(true, $"File not found: {target}", IsError: true); if (OnSendFile is not null) await OnSendFile(target); return new CommandResult(true, $"Uploading: {Path.GetFileName(target)}..."); } private async Task HandleProfile() { if (OnOpenProfile is not null) await OnOpenProfile(); return new CommandResult(true); } private async Task HandleServers() { if (OnOpenServers is not null) await OnOpenServers(); return new CommandResult(true); } private async Task HandleJoin(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /join ", IsError: true); var channel = args.Trim().TrimStart('#'); if (OnJoinChannel is not null) await OnJoinChannel(channel); return new CommandResult(true); } private async Task HandleLeave() { if (OnLeaveChannel is not null) await OnLeaveChannel(); return new CommandResult(true); } private async Task HandleTopic(string args) { if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /topic ", IsError: true); if (OnSetTopic is not null) await OnSetTopic(args.Trim()); return new CommandResult(true, $"Topic set to: {args.Trim()}"); } private async Task HandleUsers() { if (OnListUsers is not null) await OnListUsers(); return new CommandResult(true); } private async Task HandleQuit() { if (OnQuit is not null) await OnQuit(); return new CommandResult(true); } private async Task HandleHelp() { if (OnHelp is not null) await OnHelp(); return new CommandResult(true, """ Available commands: /status - Set your status /status - Set status message /nick - Set display name /color <#hex> - Set nickname color /theme - Switch theme /send - Send a file or image /profile - Open your profile /servers - Open saved servers /join - Join a channel /leave - Leave current channel /topic - Set channel topic /users - List online users /quit - Exit the app """); } private static bool IsValidHex(string s) => s.All(c => char.IsAsciiHexDigit(c)); }