using Microsoft.EntityFrameworkCore;
using PARR.Core.Common.Interfaces;
using PARR.Core.Repositories.Interfaces.Job;
using PARR.Domain.Cache.Models;
using PARR.Domain.DTOs.Matching;
using PARR.Domain.Enums;

namespace PARR.Core.Services.MatchingStatusService
{
    internal class MatchingStatusService : IMatchingStatusService
    {
        private readonly IRedisCacheService redisCacheService;
        private readonly IJobRepository jobService;
        private readonly IJobGroupRepository jobGroupService;

        public MatchingStatusService(
            IRedisCacheService redisCacheService,
            IJobRepository jobService,
            IJobGroupRepository jobGroupService
            )
        {
            this.redisCacheService = redisCacheService;
            this.jobService = jobService;
            this.jobGroupService = jobGroupService;
        }


        public async Task DeleteMatchingStatusAsync(Guid objectId, SyncTaskEntityTypeEnum type)
        {
            var key = GetKey(objectId, type);
            await redisCacheService.DeleteCachedDataAsync(key);
        }

        public async Task<MatchingStatus> GetStatusAsync(Guid objectId, SyncTaskEntityTypeEnum type)
        {
            var jobGroupIdList = new List<Guid>();
            var jobIdList = new List<Guid>();

            //формируем список jobId и jobGroupId для поиска в КЭШ, происходит ли у кого-то из них сейчас matching
            switch (type)
            {
                case SyncTaskEntityTypeEnum.Job:
                    var job = await jobService.Get().FirstOrDefaultAsync(t => t.Id == objectId);
                    if (job != null)
                    {
                        jobIdList.Add(job.Id);
                        jobGroupIdList = await jobGroupService.Get().Where(t => t.Id == job.GroupId).Select(t => t.Id).ToListAsync();
                    }
                    break;
                case SyncTaskEntityTypeEnum.JobGroup:
                    var jobGroup = await jobGroupService.Get().FirstOrDefaultAsync(t => t.Id == objectId);
                    if (jobGroup != null)
                    {
                        jobGroupIdList.Add(jobGroup.Id);
                        jobIdList = await jobService.Get().Where(t => t.GroupId == jobGroup.Id).Select(t => t.Id).ToListAsync();
                    }
                    break;
                case SyncTaskEntityTypeEnum.Template:
                    throw new Exception("Нет реализации получения кэша статуса matching для template");
                    //todo: У нас вообще нет matching для Template, позже надо удалить это вообще из Enum SyncTaskEntityTypeEnum
                    break;
            }

            // Если списки пустые, мало ли, говорим что нет matching`a
            if (!jobGroupIdList.Any() && !jobIdList.Any())
                return new MatchingStatus { DetailsJobGroups = null, DetailsJobs = null };

            // Ищем в КЭШ
            var jobGroupDetails = new List<MatchingStatusItem>();
            foreach (var jobGroupId in jobGroupIdList)
            {
                var cacheResult = await redisCacheService.GetCachedDataAsync<MatchingStatusItem>(GetKey(jobGroupId, SyncTaskEntityTypeEnum.JobGroup));
                if (cacheResult != null)
                    jobGroupDetails.Add(cacheResult);
            }

            var jobDetails = new List<MatchingStatusItem>();
            foreach (var jobId in jobIdList)
            {
                var cacheResult = await redisCacheService.GetCachedDataAsync<MatchingStatusItem>(GetKey(jobId, SyncTaskEntityTypeEnum.Job));
                if (cacheResult != null)
                    jobDetails.Add(cacheResult);
            }

            return new MatchingStatus
            {
                DetailsJobGroups = jobGroupDetails.Any() ? jobGroupDetails : null,
                DetailsJobs = jobDetails.Any() ? jobDetails : null
            };
        }

        public async Task SetMatchingStatusAsync(Guid objectId, SyncTaskEntityTypeEnum type, MatchingStatusItem data, TimeSpan cacheDuration)
        {
            var key = GetKey(objectId, type);
            await redisCacheService.SetCachedDataAsync(key, data, cacheDuration);
        }

        private string GetKey(Guid id, SyncTaskEntityTypeEnum type)
        {
            var typeStr = "";
            switch (type)
            {
                case SyncTaskEntityTypeEnum.Job:
                    typeStr = "job";
                    break;
                case SyncTaskEntityTypeEnum.JobGroup:
                    typeStr = "group";
                    break;
                case SyncTaskEntityTypeEnum.Template:
                    typeStr = "template";
                    break;
                default:
                    break;
            }

            return redisCacheService.GetKey(new string[] { "matching", typeStr, id.ToString() });
        }
    }
}
