using EchoHub.Core.Contracts;
using EchoHub.Core.DTOs;

namespace EchoHub.Server.Irc;

public class IrcBroadcaster : IChatBroadcaster
{
    private readonly IrcGatewayService _gateway;
    private readonly IMessageEncryptionService _encryption;

    public IrcBroadcaster(IrcGatewayService gateway, IMessageEncryptionService encryption)
    {
        _gateway = gateway;
        _encryption = encryption;
    }

    public async Task SendMessageToChannelAsync(string channelName, MessageDto message)
    {
        // Decrypt content for IRC clients (they can't handle app-layer encryption)
        var decryptedMessage = message with { Content = _encryption.Decrypt(message.Content) };
        var lines = IrcMessageFormatter.FormatMessage(decryptedMessage);

        foreach (var conn in _gateway.GetConnectionsInChannel(channelName))
        {
            // IRC convention: don't echo sender's own message
            if (conn.Nickname == message.SenderUsername)
                continue;

            foreach (var line in lines)
                await conn.SendAsync(line);
        }
    }

    public async Task SendUserJoinedAsync(string channelName, string username, string? excludeConnectionId = null)
    {
        foreach (var conn in _gateway.GetConnectionsInChannel(channelName))
        {
            if (conn.ConnectionId == excludeConnectionId) continue;
            await conn.SendAsync($":{username}!{username}@echohub JOIN #{channelName}");
        }
    }

    public async Task SendUserLeftAsync(string channelName, string username)
    {
        foreach (var conn in _gateway.GetConnectionsInChannel(channelName))
        {
            if (conn.Nickname == username) continue;
            await conn.SendAsync($":{username}!{username}@echohub PART #{channelName}");
        }
    }

    public async Task SendChannelUpdatedAsync(ChannelDto channel, string? channelName = null)
    {
        var target = channelName ?? channel.Name;
        if (channel.Topic is null) return;

        foreach (var conn in _gateway.GetConnectionsInChannel(target))
        {
            await conn.SendAsync($":{_gateway.Options.ServerName} TOPIC #{channel.Name} :{channel.Topic}");
        }
    }

    public Task SendUserStatusChangedAsync(List<string> channelNames, UserPresenceDto presence)
    {
        // IRC has no active status broadcast. Clients discover away via WHOIS/WHO.
        return Task.CompletedTask;
    }

    public async Task SendUserKickedAsync(string channelName, string username, string? reason)
    {
        var reasonText = reason is not null ? $" :{reason}" : "";
        foreach (var conn in _gateway.GetConnectionsInChannel(channelName))
        {
            await conn.SendAsync($":{_gateway.Options.ServerName} KICK #{channelName} {username}{reasonText}");
        }
    }

    public async Task SendUserBannedAsync(string username, string? reason)
    {
        var reasonText = reason ?? "You have been banned.";
        foreach (var conn in _gateway.GetAllConnections())
        {
            if (conn.Nickname == username)
                await conn.SendAsync($":{_gateway.Options.ServerName} NOTICE {username} :You have been banned: {reasonText}");
        }
    }

    public async Task SendMessageDeletedAsync(string channelName, Guid messageId)
    {
        foreach (var conn in _gateway.GetConnectionsInChannel(channelName))
        {
            await conn.SendAsync($":{_gateway.Options.ServerName} NOTICE {conn.Nickname ?? "*"} :Message {messageId} was deleted in #{channelName}");
        }
    }

    public async Task SendChannelNukedAsync(string channelName)
    {
        foreach (var conn in _gateway.GetConnectionsInChannel(channelName))
        {
            await conn.SendAsync($":{_gateway.Options.ServerName} NOTICE {conn.Nickname ?? "*"} :All messages in #{channelName} have been cleared");
        }
    }

    public async Task SendErrorAsync(string connectionId, string message)
    {
        if (!connectionId.StartsWith("irc-")) return;

        if (_gateway.Connections.TryGetValue(connectionId, out var conn))
        {
            await conn.SendAsync($":{_gateway.Options.ServerName} NOTICE {conn.Nickname ?? "*"} :{message}");
        }
    }

    public async Task ForceDisconnectUserAsync(List<string> connectionIds, string reason)
    {
        foreach (var connId in connectionIds)
        {
            if (!connId.StartsWith("irc-")) continue;

            if (_gateway.Connections.TryGetValue(connId, out var conn))
            {
                try
                {
                    await conn.SendAsync($"ERROR :Closing Link: {reason}");
                    await conn.DisposeAsync();
                }
                catch { /* connection may already be closed */ }
            }
        }
    }
}
