using data.RemoteData;
using data.RemoteData.DAO;
using domain.Models;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;

namespace data.Repository
{
    public class SQLPresenceRepositoryImpl : IPresenceRepository
    {
        private readonly RemoteDatabaseContext _remoteDatabaseContext;

        public SQLPresenceRepositoryImpl(RemoteDatabaseContext remoteDatabaseContext)
        {
            _remoteDatabaseContext = remoteDatabaseContext;
        }

        public void SavePresence(List<PresenceLocalEntity> presences)
        {
            foreach (var presence in presences)
            {
                var existing = _remoteDatabaseContext.PresenceDaos.FirstOrDefault(p =>
                    p.Date == DateOnly.FromDateTime(presence.Date) &&
                    p.UserGuid == presence.UserGuid &&
                    p.LessonNumber == presence.LessonNumber);

                if (existing == null)
                {
                    _remoteDatabaseContext.PresenceDaos.Add(new PresenceDao
                    {
                        Date = DateOnly.FromDateTime(presence.Date),
                        IsAttedance = presence.IsAttedance,
                        LessonNumber = presence.LessonNumber,
                        UserGuid = presence.UserGuid
                    });
                }
                else
                {
                    existing.IsAttedance = presence.IsAttedance;
                }
            }
            _remoteDatabaseContext.SaveChanges(); // Фиксация изменений
        }

        public void AddPresence(PresenceLocalEntity presence)
        {
            if (presence == null) throw new ArgumentNullException(nameof(presence));

            var newPresence = new PresenceDao
            {
                Date = DateOnly.FromDateTime(presence.Date),
                UserGuid = presence.UserGuid,
                LessonNumber = presence.LessonNumber,
                IsAttedance = presence.IsAttedance
            };
            _remoteDatabaseContext.PresenceDaos.Add(newPresence);
            _remoteDatabaseContext.SaveChanges(); // Сохраняем изменения
        }

        public List<PresenceLocalEntity> GetPresenceByGroup(int groupId)
        {
            return _remoteDatabaseContext.PresenceDaos
                .Include(p => p.UserDao)
                .Where(p => p.UserDao != null && p.UserDao.GroupID == groupId)
                .Select(p => new PresenceLocalEntity
                {
                    Date = p.Date.ToDateTime(TimeOnly.MinValue),
                    UserGuid = p.UserGuid,
                    LessonNumber = p.LessonNumber,
                    IsAttedance = p.IsAttedance
                })
                .ToList();
        }

        public List<PresenceLocalEntity> GetPresenceByGroupAndDate(int groupId, DateTime date)
        {
            return _remoteDatabaseContext.PresenceDaos
                .Include(p => p.UserDao)
                .Where(p => p.UserDao != null && p.UserDao.GroupID == groupId && p.Date == DateOnly.FromDateTime(date))
                .Select(p => new PresenceLocalEntity
                {
                    Date = p.Date.ToDateTime(TimeOnly.MinValue),
                    UserGuid = p.UserGuid,
                    LessonNumber = p.LessonNumber,
                    IsAttedance = p.IsAttedance
                })
                .ToList();
        }

        public void MarkUserAsAbsent(Guid userGuid, int firstLessonNumber, int lastLessonNumber)
        {
            var presences = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserGuid == userGuid && p.LessonNumber >= firstLessonNumber && p.LessonNumber <= lastLessonNumber)
                .ToList();

            foreach (var presence in presences)
            {
                presence.IsAttedance = false;
            }
            _remoteDatabaseContext.SaveChanges(); // Фиксация изменений
        }

        public DateOnly? GetLastDateByGroupId(int groupId)
        {
            var lastDate = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserDao != null && p.UserDao.GroupID == groupId)
                .OrderByDescending(p => p.Date)
                .Select(p => p.Date)
                .FirstOrDefault();

            return lastDate == default ? (DateOnly?)null : lastDate;
        }

        public GroupPresenceSummary GetGeneralPresenceForGroup(int groupId)
        {
            var presences = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserDao != null && p.UserDao.GroupID == groupId)
                .ToList();

            var distinctLessons = presences
                .Select(p => new { p.Date, p.LessonNumber })
                .Distinct()
                .Count();

            var userGuids = presences.Select(p => p.UserGuid).Distinct().ToList();

            double totalAttendance = presences.Count(p => p.IsAttedance);
            double totalPossibleAttendance = userGuids.Count * distinctLessons;

            var userAttendances = userGuids.Select(userGuid =>
            {
                var userPresences = presences.Where(p => p.UserGuid == userGuid).ToList();
                double attended = userPresences.Count(p => p.IsAttedance);
                double missed = userPresences.Count(p => !p.IsAttedance);

                return new UserAttendance
                {
                    UserGuid = userGuid,
                    Attended = attended,
                    Missed = missed,
                    AttendanceRate = attended + missed > 0
                        ? (attended / (attended + missed)) * 100
                        : 0
                };
            }).ToList();

            return new GroupPresenceSummary
            {
                UserCount = userGuids.Count,
                LessonCount = distinctLessons,
                TotalAttendancePercentage = totalPossibleAttendance > 0
                    ? (totalAttendance / totalPossibleAttendance) * 100
                    : 0,
                UserAttendances = userAttendances
            };
        }

        public bool UpdateAttention(Guid userGuid, int groupId, int firstLesson, int lastLesson, DateOnly date, bool isAttendance)
        {
            var presences = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserGuid == userGuid &&
                            p.UserDao != null &&
                            p.UserDao.GroupID == groupId &&
                            p.LessonNumber >= firstLesson &&
                            p.LessonNumber <= lastLesson &&
                            p.Date == date)
                .ToList();

            if (presences.Any())
            {
                foreach (var presence in presences)
                {
                    presence.IsAttedance = isAttendance;
                }
                _remoteDatabaseContext.SaveChanges();
                return true;
            }
            return false;
        }

        public List<PresenceDao> GetAttendanceByGroup(int groupId)
        {
            return _remoteDatabaseContext.PresenceDaos
                .Include(p => p.UserDao)
                .Where(p => p.UserDao != null && p.UserDao.GroupID == groupId)
                .ToList();
        }
    }
}
