using data.domain.Models;
using data.RemoteData.RemoteDatabase.DAO;
using data.RemoteData.RemoteDataBase;
using data.RemoteData.RemoteDataBase.DAO;
using System.Data;

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

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


        public List<PresenceDao> GetAttendanceByGroup(int groupId)
        {
            // Получаем записи посещаемости для указанной группы
            return _remoteDatabaseContext.PresenceDaos
                .Where(p => p.GroupId == groupId)
                .Select(p => new PresenceDao
                {
                    UserId = p.UserId,
                    GroupId = p.GroupId,
                    Date = p.Date,
                    LessonNumber = p.LessonNumber,
                    IsAttedance = p.IsAttedance
                })
                .ToList();
        }


        public List<PresenceDao> GetPresenceForAbsent(DateTime date, int GroupId)
        {
            return _remoteDatabaseContext.PresenceDaos.Where(p => p.GroupId == GroupId && p.Date == DateOnly.FromDateTime(date)).ToList();
        }
        public List<PresenceDao> GetPresenceByDateAndGroup(DateTime date, int groupId)
        {
            return _remoteDatabaseContext.PresenceDaos.Where(p => p.Date == DateOnly.FromDateTime(date) &&
                                         _remoteDatabaseContext.Users.Any(u => u.GroupId == groupId && u.UserId == p.UserId)).ToList();
        }

        // Реализация метода для получения всех данных по группе
        public List<PresenceDao> GetPresenceByGroup(int groupId)
        {
            return _remoteDatabaseContext.PresenceDaos.Where(p => p.GroupId == groupId)
                                                      .OrderBy(p => p.Date)
                                                      .ThenBy(p => p.UserId).ToList();
        }

        public void SavePresence(List<PresenceDao> presences)
        {
            _remoteDatabaseContext.PresenceDaos.AddRange(presences.Select(it => new PresenceDao
            {
                Date = it.Date,
                IsAttedance = it.IsAttedance,
                LessonNumber = it.LessonNumber,
                UserId = it.UserId,
                GroupId = it.GroupId
            }));
            _remoteDatabaseContext.SaveChanges();
        }

        public void UpdateAtt(int userId, int groupId, int firstLesson, int lastLesson, DateOnly date, bool isAttendance)
        {
            // Находим все записи по UserId, GroupId, LessonNumber (в диапазоне) и дате
            var presences = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserId == userId
                            && p.GroupId == groupId
                            && p.LessonNumber >= firstLesson
                            && p.LessonNumber <= lastLesson
                            && p.Date == date)
                .ToList();

            // Обновляем значение IsAttendance для всех найденных записей
            foreach (var presence in presences)
            {
                presence.IsAttedance = isAttendance;
            }

            _remoteDatabaseContext.SaveChanges(); // Сохраняем изменения в базе данных
        }

        public DateOnly? GetLastDateByGroupId(int groupId)
        {
            // Проверяем наличие записей о посещаемости в базе данных для данной группы.
            var lastDate = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.GroupId == groupId)
                .OrderByDescending(p => p.Date)
                .Select(p => p.Date)
                .FirstOrDefault();

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

        public List<PresenceDao> PresenceSort(List<PresenceDao> presences)
        {
            presences = _remoteDatabaseContext.PresenceDaos.OrderBy(p => p.Date).ToList();
            return presences;
        }


        public GroupAttendanceStatistics GetGeneralPresenceForGroup(int groupId)
        {
            var presences = _remoteDatabaseContext.PresenceDaos.Where(p => p.GroupId == groupId).OrderBy(p => p.LessonNumber).ToList();
            var dates = _remoteDatabaseContext.PresenceDaos;
            var distDates = dates.Select(p => p.Date).Distinct().ToList();
            int lesId = 0;
            int lesNum = 1;
            double att = 0;
            int days = -1;
            int countAllLes = 0;
            DateOnly date = DateOnly.MinValue;
            List<int> usersId = new List<int>();

            foreach (var presence in presences)
            {
                if (!usersId.Contains(presence.UserId))
                {
                    usersId.Add(presence.UserId);
                }
                if (presence.Date != date)
                {
                    date = presence.Date;
                    lesId++;
                    lesNum = presence.LessonNumber;
                    days++;
                }
                if (presence.LessonNumber != lesNum && date == presence.Date)
                {
                    lesNum = presence.LessonNumber;
                    countAllLes++;
                    lesId++;
                }


                if (presence.IsAttedance)
                {
                    att++;
                }

            }
            List<UserAttendance> a = new List<UserAttendance>();
            List<int> ids = new List<int>();
            double ok = 0;
            double skip = 0;
            int userId = 0;
            foreach (var user in usersId)
            {
                var users = _remoteDatabaseContext.PresenceDaos.Where(p => p.UserId == user);
                foreach (var usera in users)
                {
                    userId = usera.UserId;
                    if (!ids.Contains(usera.UserId))
                    {
                        skip = 0;
                        ok = 0;
                        ids.Add(userId);
                        a.Add(new UserAttendance { UserId = userId, Attended = ok, Missed = skip });
                        userId = usera.UserId;
                        if (usera.IsAttedance)
                        {
                            a.First(a => a.UserId == usera.UserId).Attended = ok += 1;
                        }
                        else
                        {
                            a.First(a => a.UserId == usera.UserId).Missed = skip += 1;
                        }
                    }
                    else
                    {
                        if (usera.IsAttedance)
                        {
                            a.First(a => a.UserId == usera.UserId).Attended = ok += 1;
                        }
                        else
                        {
                            a.First(a => a.UserId == usera.UserId).Missed = skip += 1;
                        }
                    }
                }
            }

            var statistics = new GroupAttendanceStatistics
            {
                UserCount = usersId.Count,
                TotalLessons = lesId,
                AttendancePercentage = att / usersId.Count / lesNum / distDates.Count() * 100
            };

            foreach (var user in a)
            {
                statistics.UserAttendanceDetails.Add(new UserAttendance
                {
                    UserId = user.UserId,
                    Attended = user.Attended,
                    Missed = user.Missed,
                    AttendanceRate = user.Attended / (user.Missed + user.Attended) * 100
                });
            }

            return statistics;
        }

        public List<AllPresence> AllPresence(int GroupId, DateOnly? dateStart, DateOnly? dateEnd, int? UserId)
        {
            List<AllPresence> result = new List<AllPresence>();  // Инициализируем результат.

            // Проверяем, что GroupId задан и обрабатываем остальные параметры.
            if (dateStart!=DateOnly.MinValue && dateEnd!= DateOnly.MinValue && UserId!=0)
            {
                // Если все параметры заданы, фильтруем по ним
                var presenceData = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.Date >= dateStart && p.Date <= dateEnd && p.UserId == UserId && p.GroupId == GroupId)
                    .Select(p => new
                    {
                        GroupName = _remoteDatabaseContext.Groups
                            .Where(g => g.Id == p.GroupId)
                            .Select(g => g.Name)
                            .FirstOrDefault(),
                        UserName = _remoteDatabaseContext.Users
                            .Where(u => u.UserId == p.UserId)
                            .Select(u => u.FIO)
                            .FirstOrDefault(),
                        p.LessonNumber,
                        p.Date,
                        p.IsAttedance
                    })
                    .ToList();

                result = presenceData.Select(d => new AllPresence
                {
                    GroupName = d.GroupName,
                    Users = new UsersForPresence
                    {
                        FIO = d.UserName,
                        LessonNumber = d.LessonNumber,
                        Date = d.Date,
                        isAttendance = d.IsAttedance
                    }
                }).ToList();
            }
            else if (dateStart != DateOnly.MinValue && dateEnd != DateOnly.MinValue)
            {
                // Если только даты заданы, фильтруем только по датам
                var presenceData = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.Date >= dateStart && p.Date <= dateEnd && p.GroupId == GroupId)
                    .Select(p => new
                    {
                        GroupName = _remoteDatabaseContext.Groups
                            .Where(g => g.Id == p.GroupId)
                            .Select(g => g.Name)
                            .FirstOrDefault(),
                        UserName = _remoteDatabaseContext.Users
                            .Where(u => u.UserId == p.UserId)
                            .Select(u => u.FIO)
                            .FirstOrDefault(),
                        p.LessonNumber,
                        p.Date,
                        p.IsAttedance
                    })
                    .ToList();

                result = presenceData.Select(d => new AllPresence
                {
                    GroupName = d.GroupName,
                    Users = new UsersForPresence
                    {
                        FIO = d.UserName,
                        LessonNumber = d.LessonNumber,
                        Date = d.Date,
                        isAttendance = d.IsAttedance
                    }
                }).ToList();
            }
            else if (UserId!=0)
            {
                // Если только UserId задан, фильтруем только по UserId
                var presenceData = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.UserId == UserId && p.GroupId == GroupId)
                    .Select(p => new
                    {
                        GroupName = _remoteDatabaseContext.Groups
                            .Where(g => g.Id == p.GroupId)
                            .Select(g => g.Name)
                            .FirstOrDefault(),
                        UserName = _remoteDatabaseContext.Users
                            .Where(u => u.UserId == p.UserId)
                            .Select(u => u.FIO)
                            .FirstOrDefault(),
                        p.LessonNumber,
                        p.Date,
                        p.IsAttedance
                    })
                    .ToList();

                result = presenceData.Select(d => new AllPresence
                {
                    GroupName = d.GroupName,
                    Users = new UsersForPresence
                    {
                        FIO = d.UserName,
                        LessonNumber = d.LessonNumber,
                        Date = d.Date,
                        isAttendance = d.IsAttedance
                    }
                }).ToList();
            }
            else
            {
                // Если ни даты, ни UserId не заданы, возвращаем все данные для группы
                var presenceData = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.GroupId == GroupId)
                    .Select(p => new
                    {
                        GroupName = _remoteDatabaseContext.Groups
                            .Where(g => g.Id == p.GroupId)
                            .Select(g => g.Name)
                            .FirstOrDefault(),
                        UserName = _remoteDatabaseContext.Users
                            .Where(u => u.UserId == p.UserId)
                            .Select(u => u.FIO)
                            .FirstOrDefault(),
                        p.LessonNumber,
                        p.Date,
                        p.IsAttedance
                    })
                    .ToList();

                result = presenceData.Select(d => new AllPresence
                {
                    GroupName = d.GroupName,
                    Users = new UsersForPresence
                    {
                        FIO = d.UserName,
                        LessonNumber = d.LessonNumber,
                        Date = d.Date,
                        isAttendance = d.IsAttedance
                    }
                }).ToList();
            }

            return result;
        }
        public void UpdateAttendance(List<AttendanceInputModel> attendanceList)
        {
            foreach (var attendance in attendanceList)
            {
                // Поиск существующей записи по GroupId, UserId, Date, и LessonNumber
                var existingRecord = _remoteDatabaseContext.PresenceDaos
                    .FirstOrDefault(p => p.GroupId == attendance.GroupId && p.UserId == attendance.UserId && p.Date == attendance.Date && p.LessonNumber == attendance.LessonNumber);

                if (existingRecord != null)
                {
                    // Если запись найдена, обновляем статус посещаемости
                    existingRecord.IsAttedance = attendance.IsAttendance;
                    _remoteDatabaseContext.SaveChanges();
                }
                else
                {
                    // Если записи не существует, создаем новую
                    var newRecord = new PresenceDao
                    {
                        GroupId = attendance.GroupId,
                        UserId = attendance.UserId,
                        Date = attendance.Date,
                        LessonNumber = attendance.LessonNumber,
                        IsAttedance = attendance.IsAttendance
                    };
                    _remoteDatabaseContext.PresenceDaos.Add(newRecord);
                    _remoteDatabaseContext.SaveChanges();
                }
            }
        }



        // Метод для удаления посещаемости по пользователю
        public void DeletePresenceByUser(int groupId, int userId)
        {
                // Находим все записи по пользователю и группе
                var attendanceToDelete = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.GroupId == groupId && p.UserId == userId)
                    .ToList();
                    _remoteDatabaseContext.PresenceDaos.RemoveRange(attendanceToDelete);
                    _remoteDatabaseContext.SaveChanges();
        }

        // Метод для удаления посещаемости по диапазону дат
        public void DeletePresenceByDateRange(int groupId, DateOnly startDate, DateOnly endDate)
        {
                // Находим все записи в пределах указанного диапазона дат
                var attendanceToDelete = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.GroupId == groupId && p.Date >= startDate && p.Date <= endDate)
                    .ToList();
                    _remoteDatabaseContext.PresenceDaos.RemoveRange(attendanceToDelete);
                    _remoteDatabaseContext.SaveChanges();
        }

        // Метод для удаления посещаемости по группе
        public void DeletePresenceByGroup(int groupId)
        {
                // Находим все записи по группе
                var attendanceToDelete = _remoteDatabaseContext.PresenceDaos
                    .Where(p => p.GroupId == groupId)
                    .ToList();
                    _remoteDatabaseContext.PresenceDaos.RemoveRange(attendanceToDelete);
                    _remoteDatabaseContext.SaveChanges();
        }

        // Реализация метода удаления посещаемости
        public void DeletePresences(List<PresenceDao> presences)
        {
            _remoteDatabaseContext.PresenceDaos.RemoveRange(presences);  // Удаление всех записей
            _remoteDatabaseContext.SaveChanges();
        }

        // Получение посещаемости для пользователя в группе
        public List<PresenceDao> GetPresenceByUserAndGroup(int userId, int groupId)
        {
            return _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserId == userId && p.GroupId == groupId)
                .ToList();
        }

        // Получение посещаемости по диапазону дат для группы
        public List<PresenceDao> GetPresenceByDateRange(int groupId, DateOnly startDate, DateOnly endDate)
        {
            return _remoteDatabaseContext.PresenceDaos
                .Where(p => p.GroupId == groupId && p.Date >= startDate && p.Date <= endDate)
                .ToList();
        }
        public void UpdateAttendance(int userId, int groupId, DateOnly date, int lessonNumber, bool isAttendance)
        {
            var presences = _remoteDatabaseContext.PresenceDaos
                .Where(p => p.UserId == userId
                            && p.GroupId == groupId
                            && p.Date == date
                            && p.LessonNumber == lessonNumber)
                .ToList();

            foreach (var presence in presences)
            {
                presence.IsAttedance = isAttendance;  // Обновляем состояние посещаемости
            }

            _remoteDatabaseContext.SaveChanges();  // Сохраняем изменения в базе данных
        }
    }
}
