using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using EFCore.BulkExtensions;
using Microsoft.Extensions.Options;
using OnlineAssessment.Common;
using OnlineAssessment.Domain.Models;
using OnlineAssessment.Domain.ViewModels;

namespace OnlineAssessment.Data.EFCore
{
    public class EFCoreUserGroupRepository : EfCoreRepository<UserGroups, OnlineAssessmentContext>
    {
        public readonly OnlineAssessmentContext _context;
        private readonly IMapper _mapper;
        public readonly EfCoreCommonRepository _common;

        public EFCoreUserGroupRepository(OnlineAssessmentContext context, IMapper mapper, IOptionsSnapshot<ResponseMessage> responseMessage) : base(context, responseMessage)
        {
            _context = context;
            _mapper = mapper;
            _common = new EfCoreCommonRepository(_context);
        }

        public int GetLanguageIdByCode(string language_code)
        {
            Language language = _common.GetLanguageByCode(language_code);

            if (language == null) return -1;
            int language_id = (int)language.Id;

            return language_id;
        }

        public ClassViewModel GetAnyClassById(int institute_id, int class_id)
        {
            return _common.GetAnyClassById(institute_id, class_id);
        }


        public List<UserGroupViewAllModel> GetAllUserGroupsOfTheClass(int institute_id, int class_id, string sortBy, string sortOrder)
        {
            List<UserGroupViewAllModel> iList = (from u in _context.UserGroups
                                                 
                                                 where u.ClassId == class_id && u.IsActive == true 
                                                        
                                               select new UserGroupViewAllModel
                                               {
                                                   id = u.Id,
                                                   name = u.Name,
                                                   student_count = _context.UserGroupMembers.Where(ugm => ugm.UserGroupId == u.Id && ugm.IsActive == true).Count(),
                                                   created_on = (DateTime)u.CreatedOn,
                                                   updated_on = (DateTime)u.UpdatedOn
                                               }
                                     ).ToList();



            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": iList = iList.OrderByDescending(a => a.name).ToList(); break;
                        case "CREATEDON": iList = iList.OrderByDescending(a => a.created_on).ToList(); break;
                        case "UPDATEDON": iList = iList.OrderByDescending(a => a.updated_on).ToList(); break;
                    }

                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": iList = iList.OrderBy(a => a.name).ToList(); break;
                        case "CREATEDON": iList = iList.OrderBy(a => a.created_on).ToList(); break;
                        case "UPDATEDON": iList = iList.OrderBy(a => a.updated_on).ToList(); break;
                    }
                }
            }

            return iList;
        }

        public List<UserGroupViewAllModel> GetAllUserGroups(int institute_id, int user_id, string sortBy, string sortOrder)
        {
            List<UserGroupViewAllModel> iList = (from u in _context.UserGroups
                                                 join c in _context.Classes on u.ClassId equals c.Id

                                                 where u.IsActive == true && c.InstituteId == institute_id

                                                 select new UserGroupViewAllModel
                                                 {
                                                     id = u.Id,
                                                     name = u.Name,
                                                     student_count = _context.UserGroupMembers.Where(ugm => ugm.UserGroupId == u.Id && ugm.IsActive == true).Count(),
                                                     isMember = _context.UserGroupMembers.Where(ugm => ugm.UserId == user_id && ugm.UserGroupId == u.Id && ugm.IsActive == true).Count() > 0 ? true : false,
                                                     isDefaultMember = _context.Users.Where(user => user.Id == user_id && user.BatchId == u.Id).Count() > 0 ? true : false,
                                                     created_on = (DateTime)u.CreatedOn,
                                                     updated_on = (DateTime)u.UpdatedOn
                                                 }
                                     ).ToList();


            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": iList = iList.OrderByDescending(a => a.name).ToList(); break;
                        case "CREATEDON": iList = iList.OrderByDescending(a => a.created_on).ToList(); break;
                        case "UPDATEDON": iList = iList.OrderByDescending(a => a.updated_on).ToList(); break;
                    }

                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": iList = iList.OrderBy(a => a.name).ToList(); break;
                        case "CREATEDON": iList = iList.OrderBy(a => a.created_on).ToList(); break;
                        case "UPDATEDON": iList = iList.OrderBy(a => a.updated_on).ToList(); break;
                    }
                }
            }

            return iList;
        }

        public dynamic GetUserGroupById(int institute_id, int id)
        {
            var userGroup = _common.GetUserGroupById(institute_id, id);
            return userGroup;
        }
        public dynamic GetUserGroupsByUserId(int institute_id, int user_id)
        {
            List<UserGroupViewAllModel> ugs = (from ug in _context.UserGroups
                                               join ugm in _context.UserGroupMembers on ug.Id equals ugm.UserGroupId

                                               where ug.IsActive == true
                                               && ugm.UserId == user_id && ugm.IsActive == true

                                               select new UserGroupViewAllModel
                                               {
                                                   id = ug.Id,
                                                   name = ug.Name,
                                                   created_on = (DateTime)ug.CreatedOn,
                                                   updated_on = (DateTime)ug.UpdatedOn
                                               }
                                               ).ToList();
            return ugs;
        }


        public List<UserViewModel> GetUserOfTheUserGroup(int institute_id, int user_group_id)
        {
            List<UserViewModel> iList = (from ugm in _context.UserGroupMembers
                                         join u in _context.Users on ugm.UserId equals u.Id

                                         where ugm.UserGroupId == user_group_id && ugm.IsActive == true
                                            && u.IsActive == true

                                         select new UserViewModel
                                         {
                                             id = u.Id,
                                             institute_id = u.InstituteId,
                                             role = _context.Roles.Where(r => r.Id == u.RoleId).FirstOrDefault().Code,
                                             language_code = _context.Languages.Where(l => l.Id == u.LanguageId).FirstOrDefault().Code,
                                             registration_id = u.RegistrationId,
                                             registration_from = u.RegistrationDatetime,
                                             first_name = u.FirstName,
                                             last_name = u.LastName,
                                             gender = u.Gender,
                                             email_id = u.EmailId,
                                             mobile_no = u.MobileNo,
                                             dob = u.DateOfBirth,
                                             photo = u.Photo,

                                             isActive = u.IsActive
                                         }
                                         ).ToList();

            return iList;

        }


        public int DeleteTheUserGroup(int institute_id, int user_id, int user_group_id)
        {
            try
            {
                _context.Database.BeginTransaction();

                UserGroups userGroups = _context.UserGroups.Where(u => u.Id == user_group_id
                                                        && u.IsActive == true).FirstOrDefault();

                if (userGroups == null) return (int)Message.ObjectNotFound;


                Classes cls = _context.Classes.Where(c => c.Id == userGroups.ClassId && c.InstituteId == institute_id && c.IsActive == true).FirstOrDefault();
                if(cls == null) return (int)Message.ObjectNotFound;

                userGroups.IsActive = false;
                userGroups.UpdatedOn = _common.NowIndianTime();
                userGroups.UpdatedBy = user_id;

                _context.Entry(userGroups).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();
                _context.Database.CommitTransaction();

                return userGroups.Id;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return -1;
            }

        }


        public UserGroupViewModel AddUserGroupOfTheClass(int institute_id, UserGroupAddModel newUserGroup)
        {
            try
            {
                _context.Database.BeginTransaction();

                UserGroups userGroups = new UserGroups();

                userGroups.ClassId = newUserGroup.class_id;
                userGroups.Name = newUserGroup.name;
                userGroups.Description = newUserGroup.description;
                userGroups.Photo = newUserGroup.photo;
                userGroups.IsActive = true;
                userGroups.CreatedOn = _common.NowIndianTime();
                userGroups.UpdatedOn = _common.NowIndianTime();

                _context.UserGroups.Add(userGroups);
                _context.SaveChanges();

                int newId = userGroups.Id;

                _context.Database.CommitTransaction();

                UserGroupViewModel ug = _common.GetUserGroupById(institute_id, newId);

                return ug;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        public UserGroupViewModel UpdateUserGroupOfTheInstitute(int institute_id, int usergroupID, UserGroupEditModel theUserGroup)
        {
            try
            {
                UserGroups userGroups = _context.UserGroups.Where(s => s.Id == usergroupID).FirstOrDefault();

                int count = 0;

                _context.Database.BeginTransaction();

                if (theUserGroup.Name != null && theUserGroup.Name != userGroups.Name) { userGroups.Name = theUserGroup.Name; count++; }
                if (theUserGroup.Description != null && theUserGroup.Description != userGroups.Description) { userGroups.Description = theUserGroup.Description; count++; }
                if (theUserGroup.ClassId != userGroups.ClassId) { userGroups.ClassId = theUserGroup.ClassId; count++; }
                if (theUserGroup.Photo != null && theUserGroup.Photo != userGroups.Photo) { userGroups.Photo = theUserGroup.Photo; count++; }
                if (theUserGroup.IsActive != null && theUserGroup.IsActive != userGroups.IsActive) { userGroups.IsActive = theUserGroup.IsActive; count++; }

                if (count > 0)
                {
                    userGroups.UpdatedOn = _common.NowIndianTime();
                }

                _context.UserGroups.Update(userGroups);
                _context.SaveChanges();
                _context.Database.CommitTransaction();
                return _common.GetUserGroupById(institute_id, userGroups.Id);
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }


        //This endpoint allows you to associate question to subcategories
        public int AttachUsersToUserGroup(int institute_id, int user_group_id, UserIdList userIdList, out string return_message)
        {
            int return_value = 0;

            UserGroups ug = _context.UserGroups.Where(u => u.Id == user_group_id).FirstOrDefault();
            return_message = string.Format("0 users attached the usergroup");
            if (ug == null) return 0;

            try
            {
                List<UserGroupMembers> userGroupMembersList = new List<UserGroupMembers>();
                foreach (int user_id in userIdList.IdList)
                {
                    bool isUser = _common.isUser(institute_id, user_id);
                    UserGroupMembers um = _common.GetUserGroupMembers(user_group_id, user_id);

                    if (isUser == false || um != null)
                        continue;
                    else
                    {
                        userGroupMembersList.Add(
                        new UserGroupMembers()
                        {
                            UserId = user_id,
                            UserGroupId = user_group_id,
                            IsActive = true,
                            CreatedOn = _common.NowIndianTime(),
                            UpdatedOn = _common.NowIndianTime()
                        });
                    }
                        ++return_value;
                }

                if (return_value > 0)
                {
                    _context.BulkInsert(userGroupMembersList);
                }

                return_message = string.Format("{0} users attached the usergroup", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }
            return return_value;
        }


        public int DetachUsersToUserGroup(int user_group_id, UserIdList userIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<UserGroupMembers> userGroupMembersList = new List<UserGroupMembers>();
                foreach (int user_id in userIdList.IdList)
                {
                    UserGroupMembers ugm = _common.GetUserGroupMembers(user_group_id, user_id);
                    if (ugm == null)
                        continue; //Its not there, so no need to delete/detach this
                    else
                        userGroupMembersList.Add(ugm);

                    ++return_value;
                }

                if (return_value > 0)
                {
                    _context.BulkDelete(userGroupMembersList);
                }

                return_message = string.Format("{0} users detached from the usergroup.", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }
            return return_value;
        }


    }
}
