using System.Text;
using View_by_Distance.Shared.Models.Stateless.Methods;

namespace View_by_Distance.Shared.Models.Stateless;

internal abstract class Id
{

    internal static bool NameWithoutExtensionIsIdFormat(MetadataConfiguration metadataConfiguration, string fileNameFirstSegment)
    {
        bool result;
        if (fileNameFirstSegment.Length < 5 || fileNameFirstSegment.Length > metadataConfiguration.IntMinValueLength)
            result = false;
        else
        {
            bool skipOneAllAreNumbers = fileNameFirstSegment[1..].All(char.IsNumber);
            result = (skipOneAllAreNumbers && fileNameFirstSegment[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileNameFirstSegment[0]));
        }
        return result;
    }

    internal static int GetId(MetadataConfiguration metadataConfiguration, string intelligentId)
    {
        int result;
        StringBuilder results = new();
        if (metadataConfiguration.IntMinValueLength < (metadataConfiguration.ResultConfiguration.ResultAllInOneSubdirectoryLength + 2))
            throw new NotSupportedException();
        for (int i = intelligentId.Length - (metadataConfiguration.ResultConfiguration.ResultAllInOneSubdirectoryLength + 2); i > -1; i--)
            _ = results.Append(intelligentId[i]);
        _ = results.Append(intelligentId[^3]).Append(intelligentId[^2]);
        result = int.Parse(results.ToString());
        if (intelligentId[^1] is '1' or '2')
            result *= -1;
        else if (intelligentId[^1] is not '9' and not '8')
            throw new NotSupportedException();
        return result;
    }

    internal static string GetIntelligentId(MetadataConfiguration metadataConfiguration, long id, bool? ignore)
    {
        string result;
        StringBuilder stringBuilder = new();
        if (metadataConfiguration.IntMinValueLength < (metadataConfiguration.ResultConfiguration.ResultAllInOneSubdirectoryLength + 2))
            throw new NotSupportedException();
        int key;
        string value;
        List<char> resultAllInOneSubdirectoryChars = [];
        if (id > -1)
        {
            key = ignore is not null && ignore.Value ? 8 : 9;
            value = id.ToString().PadLeft(metadataConfiguration.IntMinValueLength, '0');
        }
        else
        {
            key = ignore is not null && ignore.Value ? 2 : 1;
            value = id.ToString()[1..].PadLeft(metadataConfiguration.IntMinValueLength, '0');
        }
        for (int i = value.Length - metadataConfiguration.ResultConfiguration.ResultAllInOneSubdirectoryLength - 1; i > -1; i--)
            _ = stringBuilder.Append(value[i]);
        for (int i = value.Length - metadataConfiguration.ResultConfiguration.ResultAllInOneSubdirectoryLength; i < value.Length; i++)
            resultAllInOneSubdirectoryChars.Add(value[i]);
        result = $"{stringBuilder}{string.Join(string.Empty, resultAllInOneSubdirectoryChars)}{key}";
        return result;
    }

    internal static string GetPaddedId(MetadataConfiguration metadataConfiguration, int id, bool? ignore, int? index)
    {
        string result;
        if (metadataConfiguration.Offset < 0)
            result = Guid.NewGuid().ToString();
        else
        {
            string intelligentId = GetIntelligentId(metadataConfiguration, id, ignore);
            int check = GetId(metadataConfiguration, intelligentId);
            if (check != id)
                throw new NotSupportedException();
            result = index is null || metadataConfiguration.Offset == IId.DeterministicHashCode ? intelligentId : $"{metadataConfiguration.Offset + index}{intelligentId}";
        }
        return result;
    }

    internal static int GetDeterministicHashCode(byte[] value)
    {
        int result;
        unchecked
        {
            int hash1 = (5381 << 16) + 5381;
            int hash2 = hash1;
            for (int i = 0; i < value.Length; i += 2)
            {
                hash1 = ((hash1 << 5) + hash1) ^ value[i];
                if (i == value.Length - 1)
                    break;
                hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
            }
            result = hash1 + (hash2 * 1566083941);
        }
        return result;
    }

}