using System.Text.RegularExpressions;

namespace Pilz.Text;

public static class LikeOperator
{
    public static bool IsLike(this string? input, string pattern)
    {
        return IsLike(input, pattern, true);
    }

    public static bool IsLike(this string? input, string pattern, bool ignoreCase)
    {
        return IsLike(input, pattern, GetDefaultOptions(ignoreCase));
    }

    public static bool IsLike(this string? input, string pattern, RegexOptions options)
    {
        var resultPattern = new System.Text.StringBuilder();
        var insideList = false;
        var prevInsideList = false;

        for (var i = 0; i < pattern.Length; i++)
        {
            var c = pattern[i];
            var tempInsideList = insideList;

            // Manage pattern start
            if (i == 0 && c != '*')
                resultPattern.Append('^');

            // Manage characterlists
            if (c == '[' && !insideList)
            {
                insideList = true;
                resultPattern.Append(c);
            }
            else if (c == ']' && insideList)
            {
                insideList = false;
                resultPattern.Append(c);
            }
            else if (c == '!' && insideList && !prevInsideList)
            {
                // Special chars for Like that need to be converted
                resultPattern.Append('^');
            }
            else if (c == '?' && !insideList)
            {
                resultPattern.Append('.');
            }
            else if (c == '#' && !insideList)
            {
                resultPattern.Append(@"\d");
            }
            else if (c == '*' && i == 0)
            {
                // Nothing to append
            }
            else if (c == '*' && i == pattern.Length - 1)
            {
                // Nothing to append
            }
            else if (c == '*' && !insideList)
            {
                resultPattern.Append(".*");
            }
            else if (c == '.' || c == '\\' || c == '(' || c == ')')
            {
                // Special chars for Regex that need to be escaped
                resultPattern.Append('\\');
                resultPattern.Append(c);
            }
            else
                resultPattern.Append(c);

            // Manage pattern end
            if (i == pattern.Length - 1 && c != '*')
                resultPattern.Append('$');

            prevInsideList = tempInsideList;
        }

        return Regex.IsMatch(input, resultPattern.ToString(), options);
    }

    public static RegexOptions GetDefaultOptions(bool ignoreCase)
    {
        var options = RegexOptions.Singleline | RegexOptions.CultureInvariant;

        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;

        return options;
    }
}
