using AyCode.Core.Extensions;
using AyCode.Services.SignalRs;

namespace AyCode.Services.Server.Tests.SignalRs;

/// <summary>
/// Captured sent message for assertions.
/// </summary>
public record SentMessage(
    int MessageTag,
    ISignalRMessage Message,
    int? RequestId,
    SendTarget Target,
    string? TargetId = null)
{
    public SignalResponseDataMessage? AsDataResponse => Message as SignalResponseDataMessage;
}

/// <summary>
/// Target of the sent message.
/// </summary>
public enum SendTarget
{
    Caller,
    Client,
    Others,
    All,
    User,
    Group
}

/// <summary>
/// Helper methods for creating SignalR test messages.
/// </summary>
public static class SignalRTestHelper
{
    public static SignalParams CreateSignalParams(params object[] values)
    {
        var signalParams = new SignalParams { Status = SignalResponseStatus.Success };
        if (values.Length > 0)
            signalParams.SetParameterValues(values);
        return signalParams;
    }

    public static T? GetResponseData<T>(SentMessage sentMessage)
    {
        if (sentMessage.Message is SignalResponseDataMessage dataResponse && dataResponse.RawResponseData != null)
            return dataResponse.GetResponseData<T>();

        return default;
    }

    public static void AssertSuccessResponse(SentMessage sentMessage, int expectedTag)
    {
        if (sentMessage.Message is not SignalResponseDataMessage response)
            throw new AssertFailedException($"Response is not SignalResponseDataMessage. Type: {sentMessage.Message.GetType().Name}");

        if (response.Status != SignalResponseStatus.Success)
            throw new AssertFailedException($"Expected Success status but got {response.Status}");

        if (sentMessage.MessageTag != expectedTag)
            throw new AssertFailedException($"Expected tag {expectedTag} but got {sentMessage.MessageTag}");
    }

    public static void AssertErrorResponse(SentMessage sentMessage, int expectedTag)
    {
        if (sentMessage.Message is not SignalResponseDataMessage response)
            throw new AssertFailedException($"Response is not SignalResponseDataMessage. Type: {sentMessage.Message.GetType().Name}");

        if (response.Status != SignalResponseStatus.Error)
            throw new AssertFailedException($"Expected Error status but got {response.Status}");

        if (sentMessage.MessageTag != expectedTag)
            throw new AssertFailedException($"Expected tag {expectedTag} but got {sentMessage.MessageTag}");
    }
}
