using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore.ChangeTracking;

namespace Fast.Logic.Extensions;

public static class Extensions
{
    public static void DetachAllEntities(this ChangeTracker changeTracker)
    {
        var changedEntriesCopy = changeTracker.Entries()
            .Where(e => e.State == EntityState.Added ||
                        e.State == EntityState.Modified ||
                        e.State == EntityState.Unchanged ||
                        e.State == EntityState.Deleted)
            .ToList();

        foreach (var entry in changedEntriesCopy)
            entry.State = EntityState.Detached;
    }

    public static int TicketSort(this string ticketNum)
    {
        string masterTicketNum;

        if (string.IsNullOrEmpty(ticketNum))
            return 0;

        int subTicketDotIndex = ticketNum.IndexOf("."); //for triggers

        if (subTicketDotIndex >= 0)
            masterTicketNum = ticketNum[..ticketNum.IndexOf(".")];
        else
            masterTicketNum = ticketNum;

        var masterDigits = masterTicketNum.ToCharArray().Where(n => char.IsDigit(n));
        var masterNumeric = (masterDigits.Any() ? Convert.ToInt32(new string(masterDigits.ToArray())) : 0) * 1000;

        if (subTicketDotIndex >= 0)
        {
            string subTicketNum = ticketNum[(subTicketDotIndex + 1)..];
            var subDigits = subTicketNum.ToCharArray().Where(n => char.IsDigit(n));
            var subNumeric = (subDigits.Any() ? Convert.ToInt32(new string(subDigits.ToArray())) : 0);
            return masterNumeric + subNumeric;
        }
        else
        {
            return masterNumeric;
        }
    }

    public static bool MinBool<T>(this IEnumerable<T> source, Func<T, bool> selector)
    {
        bool ReturnBool = true;

        foreach (T value in source)
        {
            if (selector(value) == false)
            {
                ReturnBool = false;
            }
        }

        return ReturnBool;
    }

    public static string RemoveWhitespace(this string input)
    {
        return new string(input.ToCharArray()
            .Where(c => !char.IsWhiteSpace(c))
            .ToArray());
    }

    public static string RemoveJsonWhitespace(this string input)
    {
        return Regex.Replace(input, "(\"(?:[^\"\\\\]|\\\\.)*\")|\\s+", "$1");
    }

    public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize)
    {
        return source
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkSize)
            .Select(x => x.Select(v => v.Value).ToList())
            .ToList();
    }

    public static void ToFileOnDisk(this FileResult fileResult, string fileName)
    {
        if (fileResult is FileContentResult contentResult)
            File.WriteAllBytes(fileName, contentResult.FileContents);
        else if (fileResult is FileStreamResult streamResult)
        {
            using var fileStream = File.Create(fileName);
            var fileStreamResult = streamResult;
            fileStreamResult.FileStream.Seek(0, SeekOrigin.Begin);
            fileStreamResult.FileStream.CopyTo(fileStream);
            fileStreamResult.FileStream.Seek(0, SeekOrigin.Begin); //reset position to beginning. If there's any chance the FileResult will be used by a future method, this will ensure it gets left in a usable state
        }
        else
        {
            throw new ArgumentException("Unsupported FileResult type");
        }
    }

    public static string ReplaceFirstOccurrence(this string Source, string find, string replace)
    {
        string result = Source;
        int place = Source.IndexOf(find);
        if (place != -1)
            result = Source.Remove(place, find.Length).Insert(place, replace);
        return result;
    }

    public static string ReplaceLastOccurrence(this string source, string find, string replace)
    {
        string result = source;
        int place = source.LastIndexOf(find);
        if (place != -1)
            result = source.Remove(place, find.Length).Insert(place, replace);
        return result;
    }

    public static string ToSnakeCase(this string input)
    {
        if (string.IsNullOrEmpty(input)) { return input; }

        var startUnderscores = Regex.Match(input, @"^_+");
        return startUnderscores + Regex.Replace(input, @"([a-z0-9])([A-Z])", "$1_$2").ToLower();
    }
}
