using GmRelay.DiscordBot.Features.Sessions;
using GmRelay.Shared.Features.Sessions.CreateSession;
using GmRelay.Shared.Platform;

namespace GmRelay.Bot.Tests.Discord;

public sealed class DiscordSessionInteractionMapperTests
{
    [Fact]
    public void TryParseCustomId_WhenActionAndSessionIdMatch_ReturnsSessionId()
    {
        var sessionId = Guid.NewGuid();

        var result = DiscordSessionInteractionMapper.TryParseCustomId(
            $"join_session:{sessionId}",
            "join_session",
            out var parsedSessionId);

        Assert.True(result);
        Assert.Equal(sessionId, parsedSessionId);
    }

    [Fact]
    public void TryParseCustomId_WhenActionDoesNotMatch_ReturnsFalse()
    {
        var result = DiscordSessionInteractionMapper.TryParseCustomId(
            $"leave_session:{Guid.NewGuid()}",
            "join_session",
            out _);

        Assert.False(result);
    }

    [Fact]
    public void TryParseCustomId_WhenSessionIdIsInvalid_ReturnsFalse()
    {
        var result = DiscordSessionInteractionMapper.TryParseCustomId(
            "join_session:not-a-guid",
            "join_session",
            out _);

        Assert.False(result);
    }

    [Fact]
    public void CreateJoinCommand_ShouldBuildPlatformNeutralDiscordCommand()
    {
        var sessionId = Guid.NewGuid();
        var input = CreateInput(sessionId, displayName: "Alice GM");

        JoinSessionCommand command = DiscordSessionInteractionMapper.CreateJoinCommand(input);

        Assert.Equal(sessionId, command.SessionId);
        Assert.Equal("interaction-1", command.InteractionId);
        Assert.Equal(PlatformKind.Discord, command.User.Platform);
        Assert.Equal("42", command.User.ExternalUserId);
        Assert.Equal("Alice GM", command.User.DisplayName);
        Assert.Equal("alice", command.User.ExternalUsername);
        Assert.Equal(PlatformKind.Discord, command.Group.Platform);
        Assert.Equal("guild-1", command.Group.ExternalGroupId);
        Assert.Equal("channel-1", command.Group.ExternalChannelId);
        Assert.Equal(PlatformKind.Discord, command.ScheduleMessage.Platform);
        Assert.Equal("guild-1", command.ScheduleMessage.ExternalGroupId);
        Assert.Equal("message-1", command.ScheduleMessage.ExternalMessageId);
    }

    [Fact]
    public void CreateLeaveCommand_ShouldBuildPlatformNeutralDiscordCommand()
    {
        var sessionId = Guid.NewGuid();
        var input = CreateInput(sessionId, displayName: null);

        LeaveSessionCommand command = DiscordSessionInteractionMapper.CreateLeaveCommand(input);

        Assert.Equal(sessionId, command.SessionId);
        Assert.Equal("interaction-1", command.InteractionId);
        Assert.Equal(PlatformKind.Discord, command.User.Platform);
        Assert.Equal("42", command.User.ExternalUserId);
        Assert.Equal("alice", command.User.DisplayName);
        Assert.Equal("alice", command.User.ExternalUsername);
        Assert.Equal("guild-1", command.Group.ExternalGroupId);
        Assert.Equal("channel-1", command.Group.ExternalChannelId);
        Assert.Equal("message-1", command.ScheduleMessage.ExternalMessageId);
    }

    private static DiscordSessionInteractionInput CreateInput(Guid sessionId, string? displayName)
        => new(
            SessionId: sessionId,
            InteractionId: "interaction-1",
            GuildId: "guild-1",
            ChannelId: "channel-1",
            MessageId: "message-1",
            UserId: 42,
            Username: "alice",
            DisplayName: displayName);
}
