using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Common.Interfaces;
using PARR.Core.Repositories.Interfaces;
using PARR.DAL.Context;
using PARR.DAL.Repositories.Base;
using PARR.Domain.Entities;
using PARR.Domain.Settings;

namespace PARR.DAL.Repositories
{
    internal class WeekendDayRepository : BaseRepository<WeekendDay>, IWeekendDayRepository
    {
        private readonly IRedisCacheService redisCacheService;
        private readonly SettingsFromDb settings;

        public WeekendDayRepository(
            DataContext dataContext,
            ILogger<WeekendDayRepository> logger,
            IRedisCacheService redisCacheService,
            SettingsFromDb settings
            ) : base(logger, dataContext)
        {
            this.redisCacheService = redisCacheService;
            this.settings = settings;
        }


        public IQueryable<DateOnly> GetWeekends(DateOnly start, DateOnly end)
        {
            return EntitySet.Where(t => t.Date >= start && t.Date <= end).AsNoTracking().Select(t => t.Date);
        }


        public async Task<bool> IsWorkDayAsync(DateOnly date, bool useCache = false)
        {
            if (useCache)
            {
                // смотрим, есть ли в кэше рабочий день
                var workdayInCache = await redisCacheService.GetCachedDataAsync<DateOnly?>(GetWorkDayKey(date));
                if (workdayInCache != null)
                    return true;

                // смотрим, есть ли в кэше выходной день
                var weekendInCache = await redisCacheService.GetCachedDataAsync<DateOnly?>(GetWeekendKey(date));
                if (weekendInCache != null)
                    return false;
            }

            var weekendInDb = await EntitySet.FirstOrDefaultAsync(t => t.Date == date);

            var isWorkday = weekendInDb == null;

            //сохраняем всегда в КЭШ значение выходного и рабочего дня
            var cacheKey = isWorkday ? GetWorkDayKey(date) : GetWeekendKey(date);
            await redisCacheService.SetCachedDataAsync(cacheKey, date, settings.WeekendCacheTtl);

            return isWorkday;
        }


        public override async Task<bool> CreateAsync(WeekendDay obj)
        {
            // При создании выходного дня, смотрим, был ли он в кэше, если был, удаляем
            await redisCacheService.DeleteCachedDataAsync(GetWeekendKey(obj.Date));
            await redisCacheService.DeleteCachedDataAsync(GetWorkDayKey(obj.Date));

            return await base.CreateAsync(obj);
        }


        public override bool Delete(WeekendDay obj)
        {
            // При создании выходного дня, смотрим, был ли он в кэше, если был, удаляем
            redisCacheService.DeleteCachedData(GetWeekendKey(obj.Date));
            redisCacheService.DeleteCachedData(GetWorkDayKey(obj.Date));

            return base.Delete(obj);
        }


        public override async Task<bool> DeleteAsync(Guid id)
        {
            var exist = await GetAsync(id);
            if (exist == null)
            {
                logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
                return false;
            }

            return Delete(exist);
        }


        private string GetWeekendKey(DateOnly day)
        {
            //  return $"weekend_{day.ToString("yyyy-MM-dd")}";
            return redisCacheService.GetKey(new[] { "weekend", day.ToString("yyyy-MM-dd") });
        }

        private string GetWorkDayKey(DateOnly day)
        {
            //return $"workday_{day.ToString("yyyy-MM-dd")}";
            return redisCacheService.GetKey(new[] { "workday", day.ToString("yyyy-MM-dd") });
        }

    }
}
