using Stef.Validation;
using WireMock.Types;
using WireMock.Util;

namespace WireMock.Matchers.Helpers;

internal static class BodyDataMatchScoreCalculator
{
    public static MatchResult CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher)
    {
        Guard.NotNull(matcher);

        if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
        {
            switch (requestMessage?.DetectedBodyType)
            {
                case BodyType.Json:
                case BodyType.String:
                case BodyType.FormUrlEncoded:
                    return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsString);

                case BodyType.Bytes:
                    return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes);

                default:
                    return default;
            }
        }

        if (matcher is ExactObjectMatcher exactObjectMatcher)
        {
            // If the body is a byte array, try to match.
            var detectedBodyType = requestMessage?.DetectedBodyType;
            if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
            {
                return exactObjectMatcher.IsMatch(requestMessage?.BodyAsBytes);
            }
        }

        // Check if the matcher is a IObjectMatcher
        if (matcher is IObjectMatcher objectMatcher)
        {
            // If the body is a JSON object, try to match.
            if (requestMessage?.DetectedBodyType == BodyType.Json)
            {
                return objectMatcher.IsMatch(requestMessage.BodyAsJson);
            }

            // If the body is a byte array, try to match.
            if (requestMessage?.DetectedBodyType == BodyType.Bytes)
            {
                return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
            }
        }

        // Check if the matcher is a IStringMatcher
        if (matcher is IStringMatcher stringMatcher)
        {
            // If the body is a Json or a String, use the BodyAsString to match on.
            if (requestMessage?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
            {
                return stringMatcher.IsMatch(requestMessage.BodyAsString);
            }
        }

        return default;
    }
}