namespace PARR.Domain.Cache
{
    /// <summary>
    /// Ключи для кэша
    /// </summary>
    public static class CacheKeys
    {
        #region Пример
        // Пример для русских букв
        //public static class Test
        //{
        //    // Если нужно конвертировать русские буквы
        //    public static (string[], string[]) Ttt(string workGroup) => (["shortcode"], [workGroup]);
        //}
        #endregion 

        /// <summary>
        /// Имя bucket
        /// </summary>
        private const string BucketName = "bucket";


        /// <summary>
        /// Авторизация пользователей, сессии
        /// </summary>
        public static class UserAuth
        {
            /// <summary>
            /// Авторизированный пользователь
            /// </summary>
            /// <param name="ipAddress"></param>
            /// <returns></returns>
            public static string[] Session(string ipAddress) => ["user", "session", ipAddress];

            /// <summary>
            /// Заблокированный пользователь
            /// </summary>
            /// <param name="ipAddress"></param>
            /// <returns></returns>
            public static string[] Banned(string ipAddress) => ["user", "banned", ipAddress];
        }

        /// <summary>
        /// Отчеты о загруженности
        /// </summary>
        public static class Workload
        {
            /// <summary>
            /// Ключ для Template Hash 
            /// </summary>
            /// <returns></returns>
            public static string[] TemplateHash() => ["template", "report", "params"];

            /// <summary>
            /// Ключ Template внутри Hash
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public static string[] Template(Guid id) => [id.ToString()];

            /// <summary>
            /// Отчет о загруженности, все ЗО
            /// </summary>
            /// <returns></returns>
            public static string[] WorkloadResponseAreaAll() => ["workload", "response-area", "all"];

            /// <summary>
            /// Отчет о загруженности, одна ЗО
            /// </summary>
            /// <returns></returns>
            public static string[] WorkloadResponseAreaItem() => ["workload", "response-area", "item"];

            /// <summary>
            /// Отчет о загруженности, все РГ
            /// </summary>
            /// <returns></returns>
            public static string[] WorkloadWorkGroupAll() => ["workload", "work-group", "all"];

            /// <summary>
            /// Отчет о загруженности, одна РГ
            /// </summary>
            public static string[] WorkloadWorkGroupItem() => ["workload", "work group", "item"];
        }

        /// <summary>
        /// Юниты
        /// </summary>
        public static class Unit
        {
            /// <summary>
            /// Ключ для Unit Hash с bucket
            /// </summary>
            /// <param name="unitId"></param>
            /// <returns></returns>
            public static string[] UnitHashWithBucket(Guid unitId) => ["unit", BucketName, GetBucketKey(unitId)];

            /// <summary>
            /// Ключ Unit внутри Hash
            /// </summary>
            /// <param name="unitId"></param>
            /// <returns></returns>
            public static string[] UnitItem(Guid unitId) => [unitId.ToString()];
        }



        #region Helpers

        /// <summary>
        /// Получить имя (номер) bucket по id.
        /// Оптимальное кол-во элементов в бакете 512-1000 (если больше, оптимизировать настройки Redis).
        /// </summary>
        /// <param name="id"></param>
        /// <param name="bucketSize">Кол-во bucket`ов</param>
        /// <returns></returns>
        private static string GetBucketKey(Guid id, BucketSize bucketSize = BucketSize.Size256)
        {
            // Получаем GUID в виде строки без дефисов (32 символа)
            string guidString = id.ToString("N");

            //4096

            // Берем первые xx символа как срез памяти (без аллокации новой строки)
            ReadOnlySpan<char> hexPart = guidString.AsSpan(0, (int)bucketSize);

            // Конвертируем Hex в обычное число byte
            if (!int.TryParse(hexPart, System.Globalization.NumberStyles.HexNumber, null, out int bucketId))
            {
                // На случай непредвиденных сбоев, хотя для валидного GUID это невозможно
                bucketId = 0;
            }

            return bucketId.ToString();
        }

        /// <summary>
        /// Кол-во возможных bucket. 
        /// В bucket оптимально размещать до 1000 записей, если больше, то требуется переконфигурация redis
        /// </summary>
        private enum BucketSize
        {
            /// <summary>
            /// Для 256 bucket`ов - берем 2 символа
            /// </summary>
            Size256 = 2,

            /// <summary>
            /// Для 4096 bucket`ов - берем 3 символа
            /// </summary>
            Size4096 = 3
        }

        #endregion

    }
}
