using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
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 EFCoreInstituteRepository : EfCoreRepository<Institutes, OnlineAssessmentContext>
    {
        public readonly OnlineAssessmentContext _context;
        public readonly EfCoreCommonRepository _common;
        private readonly IMapper _mapper;
        public EFCoreInstituteRepository(OnlineAssessmentContext context, IMapper mapper, IOptionsSnapshot<ResponseMessage> responseMessage) : base(context, responseMessage)
        {
            _context = context;
            _mapper = mapper;
            _common = new EfCoreCommonRepository(_context, mapper);
        }

        public List<InstituteViewModel> GetListOfInstitutes()
        {
            List<Institutes> instituteList = _context.Institutes.ToList();
            List<InstituteViewModel> iList = _mapper.MapList<Institutes, InstituteViewModel>(instituteList);
            return iList;
        }

        public List<InstituteViewModel> GetListOfInstitutes(bool? isActive, int? stateId, string city, string sortBy, string sortOrder)
        {
            List<Institutes> instituteList;

            //Filtering active records
            if (isActive == null)
                instituteList = _context.Institutes.ToList();
            else
                instituteList = _context.Institutes.Where(i => i.IsActive == isActive).ToList();

            //Filtering State
            if (stateId != null && stateId > 0)
            {
                instituteList = instituteList.Where(i => i.StateId == stateId).ToList();
            }

            //Filtering city
            if (city != null && city.ToString().Trim().Length > 0)
            {
                instituteList = instituteList.Where(i => i.City == city).ToList();
            }

            //Sort by
            if (sortOrder != null && sortOrder.ToUpper() == "A")
            {
                if (sortBy.ToUpper() == "STATE")
                {
                    instituteList = instituteList.OrderBy(i => i.StateId).ToList();
                }
                else if (sortBy.ToUpper() == "CITY")
                {
                    instituteList = instituteList.OrderBy(i => i.City).ToList();
                }
                else if (sortBy.ToUpper() == "NAME")
                {
                    instituteList = instituteList.OrderBy(i => i.Name).ToList();
                }
            }
            else if (sortOrder != null && sortOrder.ToUpper() == "D")
            {
                if (sortBy.ToUpper() == "STATE")
                {
                    instituteList = instituteList.OrderByDescending(i => i.StateId).ToList();
                }
                else if (sortBy.ToUpper() == "CITY")
                {
                    instituteList = instituteList.OrderByDescending(i => i.City).ToList();
                }
                else if (sortBy.ToUpper() == "NAME")
                {
                    instituteList = instituteList.OrderByDescending(i => i.Name).ToList();
                }
            }

            List<InstituteViewModel> iList = _mapper.MapList<Institutes, InstituteViewModel>(instituteList);
            return iList;
        }

        public dynamic GetInstituteById(int id)
        {
            return _common.GetInstituteDetailById(id);
        }

        public async Task<InstituteViewModel> AddInstitute(InstituteAddModel i)
        {

            //Institutes newInstitutes = _mapper.Map<InstituteAddModel, Institutes>(institute);
            Institutes ni = new Institutes();

            ni.Name = i.Name;
            ni.Domain = i.Domain;
            ni.ApiKey = i.ApiKey;
            ni.DateOfEstablishment = i.DateOfEstablishment;
            ni.Address = i.Address;
            ni.City = i.City;
            ni.PinCode = i.PinCode;
            ni.StateId = i.StateId;
            ni.SubscriptionId = i.SubscriptionId;
            ni.IsActive = i.IsActive;

            _context.Institutes.Add(ni);
            await _context.SaveChangesAsync();

            InstituteViewModel new_institute = _common.GetInstituteDetailById(ni.Id);

            return new_institute;
        }

        public InstituteViewModel UpdateInstitute(InstituteEditModel i)
        {
            //throw new NotImplementedException();

            Institutes ni = _context.Institutes.Where(a => a.Id == i.Id).FirstOrDefault();

            if (i.Name != null) ni.Name = i.Name;
            if (i.Domain != null) ni.Domain = i.Domain;
            if (i.ApiKey != null) ni.ApiKey = i.ApiKey;
            if (i.DateOfEstablishment != null) ni.DateOfEstablishment = i.DateOfEstablishment;
            if (i.Address != null) ni.Address = i.Address;
            if (i.City != null) ni.City = i.City;
            if (i.PinCode != null) ni.PinCode = i.PinCode;
            if (i.StateId > 0) ni.StateId = i.StateId;
            if (i.SubscriptionId > 0) ni.SubscriptionId = i.SubscriptionId;
            ni.IsActive = i.IsActive;

            _context.Institutes.Update(ni);
            _context.SaveChanges();

            InstituteViewModel new_institute = _common.GetInstituteDetailById(ni.Id);

            return new_institute;
        }

        public string GetTheme(int id)
        {
            string color = _context.Institutes.Where(i => i.Id == id && i.IsActive == true).FirstOrDefault().Theme;
            return color;
        }

        public string UpdateTheme(int id, int user_id, string color)
        {
            try
            {
                Institutes institutes = _context.Institutes.Where(i => i.Id == id && i.IsActive == true).FirstOrDefault();
                if (institutes == null) return null;
                
                _context.Database.BeginTransaction();
                institutes.UpdatedBy = user_id;
                institutes.UpdatedOn = _common.NowIndianTime();
                institutes.Theme = color;

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

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

            return color;
        }

        public List<UserViewModel> GetUserOfTheInstitution(int institute_id, int roleId, string sortBy, string sortOrder)
        {
            List<Users> users;
            List<UserViewModel> userList = new List<UserViewModel>();

            users = _context.Users.Where(u => u.InstituteId == institute_id && u.RoleId == roleId && u.IsActive == true).ToList();

            //Sorting 
            if (sortOrder == null || sortOrder.ToUpper().Equals("A"))
            {
                if (sortBy == null)
                {
                    users = users.OrderBy(a => a.Id).ToList();
                }
                else if (sortBy.ToUpper().Equals("NAME"))
                {
                    users = users.OrderBy(a => a.FirstName).ToList();
                }
                else if (sortBy.ToUpper().Equals("CITY"))
                {
                    users = users.OrderBy(a => a.City).ToList();
                }
                else if (sortBy.ToUpper().Equals("PIN"))
                {
                    users = users.OrderBy(a => a.PinCode).ToList();
                }
            }
            else if (sortOrder != null && sortOrder.ToUpper().Equals("D"))
            {
                if (sortBy == null)
                {
                    users = users.OrderByDescending(a => a.Id).ToList();
                }
                else if (sortBy.ToUpper().Equals("NAME"))
                {
                    users = users.OrderByDescending(a => a.FirstName).ToList();
                }
                else if (sortBy.ToUpper().Equals("CITY"))
                {
                    users = users.OrderByDescending(a => a.City).ToList();
                }
                else if (sortBy.ToUpper().Equals("PIN"))
                {
                    users = users.OrderByDescending(a => a.PinCode).ToList();
                }
            }

            foreach (Users u in users)
            {
                UserViewModel user = new UserViewModel();
                user = _common.GetUserById(institute_id, u.Id);
                userList.Add(user);
            }

            return userList;
        }


        #region Clasess

        public ClassViewModel GetClassById(int institute_id, int id)
        {
            return _common.GetClassById(institute_id, id);
        }

        public ClassStructureViewModel GetClassStructurebyId(int institute_id, int id)
        {
            ClassStructureViewModel cStruct = (from c in _context.Classes

                                  where c.Id == id && c.InstituteId == institute_id && c.IsActive == true

                                  select new ClassStructureViewModel
                                  {
                                      id = c.Id,
                                      name = c.Name
                                  }).FirstOrDefault();

            if (cStruct == null) return null;

            cStruct.subjects = (from s in _context.Subjects
                       where s.ClassId == cStruct.id && s.IsActive == true

                       select new SubjectModel
                       {
                            id = s.Id,
                            name = s.Name,
                            topics = (from c in _context.Categories where c.SubjectId == s.Id && c.IsActive == true select new TopicModel {id = c.Id, name = c.Name}).ToList()
                       }).ToList();


            return cStruct;
        }

        public List<ClassViewModel> GetClassesOfTheInstitution(int institute_id, string sortBy, string sortOrder)
        {
            List<ClassViewModel> classViewModelList = new List<ClassViewModel>();
            List<Classes> classesList = new List<Classes>();

            classesList = _context.Classes.Where(i => i.InstituteId == institute_id && i.IsActive == true).ToList();
            
            if (sortOrder == null || sortOrder.ToUpper().Equals("A"))
            {
                if (sortBy == null)
                {
                    classesList = classesList.OrderBy(a => a.Id).ToList();
                }
                //else if (sortBy.ToUpper().Equals("NAME"))
                //{
                //    classesList = classesList.OrderBy(a => a.Name).ToList();
                //}
            }
            else if (sortOrder == null || sortOrder.ToUpper().Equals("D"))
            {
                if (sortBy == null)
                {
                    classesList = classesList.OrderByDescending(a => a.Id).ToList();
                }
                //else if (sortBy.ToUpper().Equals("NAME"))
                //{
                //    classesList = classesList.OrderByDescending(a => a.Name).ToList();
                //}
            }

            List<ClassViewModel> result = (from c in classesList
                                           
                                           where c.InstituteId == institute_id
                                           select new ClassViewModel
                                           {
                                               id = c.Id,
                                               name = c.Name,
                                               isActive = c.IsActive
                                           }).ToList();

            return result;

        }


        


        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 GetClassByID(int institute_id, int class_id)
        {
            return _common.GetClassById(institute_id, class_id);
        }


        public ClassViewModel AddNewClassOfTheInstitution(int institute_id, int user_id, string newName)
        {
            ClassViewModel cv = new ClassViewModel();
            try
            {
                _context.Database.BeginTransaction();

                Classes c = new Classes();
                c.InstituteId = institute_id;
                c.Name = newName;
                c.CreatedOn = _common.NowIndianTime();
                c.CreatedBy = user_id;
                c.UpdatedOn = _common.NowIndianTime();
                c.UpdatedBy = user_id;
                c.IsActive = true;
                _context.Classes.Add(c);
                _context.SaveChanges();

                int newClassId = c.Id;

                cv.id = newClassId;
                cv.name = newName;
                cv.slug = newName;
                cv.isActive = true;
                
                _context.Database.CommitTransaction();
            }
            catch
            {
                _context.Database.RollbackTransaction();
                cv = null;
            }
            return cv;
        }

        public ClassViewModel UpdateClassOfTheInstitution(int institute_id, int user_id, int class_id, string newName)
        {
            try
            {
                _context.Database.BeginTransaction();

                Classes classes = _context.Classes.Where(c => c.Id == class_id && c.InstituteId == institute_id && c.IsActive == true).FirstOrDefault();
                
                if(classes == null || newName == null || newName.Length == 0)
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                int count = 0;

                if (newName != null && newName != classes.Name) { classes.Name = newName; count++; }

                ClassViewModel cvm = null;

                if (count > 0)
                {
                    classes.UpdatedBy = user_id;
                    classes.UpdatedOn = _common.NowIndianTime();

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

                    cvm = GetClassById(institute_id, classes.Id);
                }                

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

        public int DeleteClassOfTheInstitution(int institute_id, int user_id, int class_id)
        {
            try
            {
                _context.Database.BeginTransaction();

                Classes classes = _context.Classes.Where(c => c.Id == class_id && c.InstituteId == institute_id 
                                                        && c.IsActive == true).FirstOrDefault();

                
                if (classes == null) return (int)Message.NotAllowedToResource;

                //Check : if question associated then cant delete the class
                int count = (from q in _context.QuestionCategories
                             join c in _context.Categories on q.CategoryId equals c.Id
                             join sub in _context.Subjects on c.SubjectId equals sub.Id
                             join cls in _context.Classes on sub.ClassId equals cls.Id

                             where cls.Id == classes.Id
                                   && q.IsActive == true


                             select q).ToList().Count;

                if (count > 0) return (int)Message.NotAllowedToResource;


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

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

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


        #endregion

        #region Subjects

        public List<SubjectViewModel> GetSubjectsOfTheClass(int institute_id, int class_id, int subject_id, string sortBy, string sortOrder)
        {
            //Get all active subjects under class_id where subject language is same as language_id
            List<SubjectViewModel> subjectsList = (from s in _context.Subjects
                                             join c in _context.Classes on s.ClassId equals c.Id

                                             where c.InstituteId == institute_id && c.Id == class_id && c.IsActive == true
                                             && s.IsActive == true
                                             
                                             select new SubjectViewModel
                                             {
                                                 id = s.Id,
                                                 name = s.Name,
                                                 isActive = s.IsActive,
                                                 last_updated = s.UpdatedOn
                                             }).ToList();

            if (subject_id != null) subjectsList.Where(s => s.id == subject_id).FirstOrDefault();

            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": subjectsList = subjectsList.OrderByDescending(a => a.name).ToList(); break;
                        case "DATE": subjectsList = subjectsList.OrderByDescending(a => a.last_updated).ToList(); break;
                    }

                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": subjectsList = subjectsList.OrderBy(a => a.name).ToList(); break;
                        case "DATE": subjectsList = subjectsList.OrderBy(a => a.last_updated).ToList(); break;
                    }
                }
            }

            return subjectsList;
        }


        public SubjectViewModel GetSubjectById(int institute_id,  int subject_id)
        {
            SubjectViewModel svm = _common.GetSubjectById(institute_id, subject_id);

            return svm;
        }

        public SubjectViewModel AddSubjectOfTheClass(int institute_id, int class_id, int user_id, SubjectAddModel newSubject)
        {
            try
            {
                Subjects subjects = new Subjects();

                _context.Database.BeginTransaction();

                subjects.ClassId = class_id;
                subjects.Name = newSubject.name;
                subjects.CreatedOn = _common.NowIndianTime();
                subjects.CreatedBy = user_id;
                subjects.UpdatedOn = _common.NowIndianTime();
                subjects.UpdatedBy = user_id;
                subjects.IsActive = true;

                _context.Subjects.Add(subjects);
                _context.SaveChanges();

                int newSubjectId = subjects.Id;

                _context.Database.CommitTransaction();

                SubjectViewModel subject = _common.GetSubjectById(institute_id, newSubjectId);

                return subject;
            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return null;
            } 
        }

        public SubjectViewModel UpdateSubjectOfTheInstitution(int institute_id, int user_id, int subject_id, string newName)
        {
            try
            {
                _context.Database.BeginTransaction();

                Subjects subject = (from s in _context.Subjects
                                    join c in _context.Classes on s.ClassId equals c.Id

                                    where c.InstituteId == institute_id && c.IsActive == true
                                    && s.Id == subject_id && s.IsActive == true
                                    
                                    select new Subjects()).FirstOrDefault();

                if (subject == null)
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                int count = 0;

                if (newName != null && newName != subject.Name) { subject.Name = newName; count++; }

                SubjectViewModel svm = null;

                if (count > 0)
                {
                    subject.UpdatedBy = user_id;
                    subject.UpdatedOn = _common.NowIndianTime();

                    _context.Entry(subject).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                    _context.SaveChanges();
                    _context.Database.CommitTransaction();
                    svm = _common.GetSubjectById(institute_id, subject.Id);
                }

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

        public int DeleteSubjectById(int institute_id, int user_id, int subject_id)
        {
            try
            {
                Subjects subject = (from s in _context.Subjects
                                    join c in _context.Classes on s.ClassId equals c.Id

                                    where c.InstituteId == institute_id && c.IsActive == true 
                                    && s.Id == subject_id && s.IsActive == true

                                    select s
                                    ).FirstOrDefault();

                if (subject == null) return (int)Message.NotAllowedToResource;


                //Check : if question associated then cant delete the subject
                int count = (from q in _context.QuestionCategories
                             join c in _context.Categories on q.CategoryId equals c.Id
                             join sub in _context.Subjects on c.SubjectId equals sub.Id

                             where sub.Id == subject.Id
                                   && q.IsActive == true

                             select q).ToList().Count;

                if (count > 0) return (int)Message.NotAllowedToResource;

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

                _context.Entry(subject).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();

                return subject.Id;
            }
            catch
            {
                return -1;
            }
        }

        #endregion


        #region Categories
        public List<CategoryViewModel> GetCategoriesOfTheSubject(int institute_id, int subject_id, int category_id, string sortBy, string sortOrder)
        {
            //Get all active subjects under class_id where subject language is same as language_id
            List<CategoryViewModel> categoriesList = (from cat in _context.Categories
                                                       join s in _context.Subjects on cat.SubjectId equals s.Id
                                                       join c in _context.Classes on s.ClassId equals c.Id

                                                       where c.InstituteId == institute_id && c.IsActive == true
                                                       && s.Id == subject_id && s.IsActive == true
                                                       && cat.IsActive == true

                                                   select new CategoryViewModel
                                                   {
                                                       id = cat.Id,
                                                       name = cat.Name,
                                                       isActive = cat.IsActive,
                                                       last_updated = cat.UpdatedOn
                                                   }).ToList();

            if (category_id != null) categoriesList.Where(c => c.id == category_id).FirstOrDefault();

            if (categoriesList != null && categoriesList.Count > 0)
            {

                if ((sortBy != null && sortBy.Length > 0) || (sortOrder != null && sortOrder.Length > 0))
                {
                    if (sortOrder == null || sortOrder.Length == 0 || sortOrder == "A")
                    {
                        switch (sortOrder)
                        {
                            case "NAME": categoriesList = categoriesList.OrderBy(c => c.name).ToList(); break;
                            case "DATE": categoriesList = categoriesList.OrderBy(c => c.last_updated).ToList(); break;
                        }

                    }
                    else if (sortOrder != null && sortOrder.Length > 0 && sortOrder == "D")
                    {
                        switch (sortOrder)
                        {
                            case "NAME": categoriesList = categoriesList.OrderByDescending(c => c.name).ToList(); break;
                            case "DATE": categoriesList = categoriesList.OrderByDescending(c => c.last_updated).ToList(); break;
                        }
                    }
                }
            }

            return categoriesList;
        }


        public CategoryViewModel GetCategoryByID(int institute_id, int language_id, int category_id)
        {
            return _common.GetCategoryById(institute_id, category_id);
        }

        public CategoryViewModel AddCategoryOfTheSubject(int institute_id, int subject_id, int user_id, CategoryAddModel newCategory)
        {
            SubjectViewModel subject = (from s in _context.Subjects 
                                           join c in _context.Classes on s.ClassId equals c.Id

                                           where c.InstituteId == institute_id && c.IsActive == true
                                            && s.Id == subject_id && s.IsActive == true
                                                      
                                           select new SubjectViewModel
                                           {
                                                id = s.Id,
                                                name = s.Name,
                                                isActive = s.IsActive,
                                                last_updated = s.UpdatedOn
                                           }).FirstOrDefault();

            if (subject == null) return null;

            try
                {
                    Categories categories = new Categories();

                    _context.Database.BeginTransaction();

                    categories.SubjectId = subject_id;
                    categories.Name = newCategory.name;
                    categories.CreatedOn = _common.NowIndianTime();
                    categories.CreatedBy = user_id;
                    categories.UpdatedOn = _common.NowIndianTime();
                    categories.UpdatedBy = user_id;

                    categories.IsActive = true;
                    

                    _context.Categories.Add(categories);
                    _context.SaveChanges();

                    int newCategoryId = categories.Id;

                    _context.Database.CommitTransaction();

                    CategoryViewModel category = _common.GetCategoryById(institute_id, newCategoryId);

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

        public CategoryViewModel UpdateCategoryByID(int institute_id, int category_id, int user_id, string newName)
        {
            
            try
            {
                _context.Database.BeginTransaction();
                
                //verify validity of category id wrt institute
                Categories categories = (from c in _context.Categories
                                         join s in _context.Subjects on c.SubjectId equals s.Id
                                         join cls in _context.Classes on s.ClassId equals cls.Id

                                         where cls.InstituteId == institute_id && cls.IsActive == true
                                         && c.Id == category_id && c.IsActive == true
                                         select new Categories()).FirstOrDefault();
                
                if (categories == null)
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                int count = 0;

                if (newName != null && newName != categories.Name) { categories.Name = newName; count++; }

                if (count > 0)
                {
                    categories.UpdatedBy = user_id;
                    categories.UpdatedOn = _common.NowIndianTime();
                }

                _context.Entry(categories).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();

                _context.Database.CommitTransaction();
                CategoryViewModel cvm = _common.GetCategoryById(institute_id, category_id);

                return cvm;

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

        public int DeleteCategoryByID(int institute_id, int user_id, int category_id)
        {
            try
            {
                _context.Database.BeginTransaction();

                //verify validity of category id wrt institute
                Categories category = (from c in _context.Categories
                                         join s in _context.Subjects on c.SubjectId equals s.Id
                                         join cls in _context.Classes on s.ClassId equals cls.Id

                                         where cls.InstituteId == institute_id && cls.IsActive == true
                                         && c.Id == category_id && c.IsActive == true
                                         select c).FirstOrDefault();

                if (category == null)
                {
                    _context.Database.RollbackTransaction();
                    return (int)Message.NotAllowedToResource;
                }

                //Check : if question associated then cant delete the category
                int count = (from q in _context.QuestionCategories
                             join c in _context.Categories on q.CategoryId equals c.Id

                             where c.Id == category.Id
                                   && q.IsActive == true

                             select q).ToList().Count;

                if (count > 0) return (int)Message.NotAllowedToResource;

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

                _context.Entry(category).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();

                _context.Database.CommitTransaction();
                return category.Id;
            }
            catch
            {
                return 0;
            }
        }

        public bool CheckIfUserExist(int user_id, int institute_id)
        {
            return _common.CheckIfUserExist(institute_id, user_id);
        }
        #endregion
        /*

        #region Sub Categories 
    
        public List<SubCategoryViewModel> GetAllSubCategoriesOfTheCategory(int institute_id, int language_id, int category_id, string sortBy, string sortOrder)
        {
            List<SubCategoryViewModel> subCategoryViewModelList = (from sc in _context.SubCategories
                                                                   join scl in _context.SubCategoryLanguages on sc.Id equals scl.SubcategoryId
                                                                   join c in _context.Categories on sc.CategoryId equals c.Id
                                                                   join s in _context.Subjects on c.SubjectId equals s.Id
                                                                   join cls in _context.Classes on s.ClassId equals cls.Id
                                                                   where cls.InstituteId == institute_id 
                                                                        && sc.CategoryId == category_id && sc.IsActive == true
                                                                        && scl.LanguageId == language_id && scl.IsActive == true
                                                                        && c.IsActive == true 
                                                                   select new SubCategoryViewModel
                                                                   {
                                                                       Id = sc.Id,
                                                                       Name = scl.Name,
                                                                       Description = scl.Description,

                                                                       IsActive = scl.IsActive
                                                                   }
                          ).ToList();


            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": subCategoryViewModelList = subCategoryViewModelList.OrderByDescending(a => a.Name).ToList(); break;
                        case "ID": subCategoryViewModelList = subCategoryViewModelList.OrderByDescending(a => a.Id).ToList(); break;
                    }

                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": subCategoryViewModelList = subCategoryViewModelList.OrderBy(a => a.Name).ToList(); break;
                        case "ID": subCategoryViewModelList = subCategoryViewModelList.OrderBy(a => a.Id).ToList(); break;
                    }
                }
            }

            return subCategoryViewModelList;

        }


        public SubCategoryViewModel GetSubCategoryByID(int institute_id, int language_id, int sub_category_id)
        {
            return _common.GetSubCategoryById(institute_id, language_id, sub_category_id);
        }

        public SubCategoryViewModel AddSubCategoryOfTheCategory(int institute_id, string language_code, int category_id, int user_id, SubCategoryAddModel newSubCategory)
        {
            Language language = _common.GetLanguageByCode(language_code);

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

            try
            {
                _context.Database.BeginTransaction();

                SubCategories subCategories = new SubCategories();

                subCategories.CategoryId = category_id;
                subCategories.CreatedBy = user_id;
                subCategories.CreatedOn = _common.NowIndianTime();
                subCategories.IsActive = true;
                _context.SubCategories.Add(subCategories);
                _context.SaveChanges();

                int newId = subCategories.Id;


                SubCategoryLanguages subCategoryLanguages = new SubCategoryLanguages();
                subCategoryLanguages.CategoryId = category_id;
                subCategoryLanguages.SubcategoryId = newId;
                subCategoryLanguages.LanguageId = language_id;
                subCategoryLanguages.Name = newSubCategory.Name;
                subCategoryLanguages.Description = newSubCategory.Description;
                subCategoryLanguages.IsActive = true;
                subCategoryLanguages.CreatedOn = _common.NowIndianTime();
                subCategoryLanguages.CreatedBy = user_id;

                _context.SubCategoryLanguages.Add(subCategoryLanguages);
                _context.SaveChanges();

                _context.Database.CommitTransaction();

                SubCategoryViewModel svm = _common.GetSubCategoryById(institute_id, language_id, newId);

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

        public SubCategoryViewModel UpdateSubCategoryByID(int institute_id, string language_code, int user_id, SubCategoryEditModel theSubCategory)
        {
            Language language = _common.GetLanguageByCode(language_code);

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

            try
            {
                _context.Database.BeginTransaction();

                SubCategories subcategories = _context.SubCategories.Where(s => s.Id == theSubCategory.Id && s.IsActive == true).FirstOrDefault();
                SubCategoryLanguages subcategoryLanguages = _context.SubCategoryLanguages.
                    Where(s => s.SubcategoryId == theSubCategory.Id).
                    Where(s => s.LanguageId == language_id).
                    Where(s => s.IsActive == true).FirstOrDefault();

                if (subcategories == null || subcategories == null || theSubCategory == null)
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                int count = 0;

                if (theSubCategory.Name != null && theSubCategory.Name != subcategoryLanguages.Name) { subcategoryLanguages.Name = theSubCategory.Name; count++; }
                if (theSubCategory.Description != null && theSubCategory.Description != subcategoryLanguages.Description) { subcategoryLanguages.Description = theSubCategory.Description; count++; }

                if (count > 0)
                {
                    subcategories.UpdatedBy = user_id;
                    subcategories.UpdatedOn = _common.NowIndianTime();

                    subcategoryLanguages.UpdatedOn = _common.NowIndianTime();
                    subcategoryLanguages.UpdatedBy = user_id;
                }

                _context.Entry(subcategories).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();

                _context.Entry(subcategoryLanguages).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();

                _context.Database.CommitTransaction();
                SubCategoryViewModel svm = _common.GetSubCategoryById(institute_id, language_id, theSubCategory.Id);

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

        }
        public int DeleteSubCategoryByID(string language_code, int user_id, int sub_category_id)
        {
            Language language = _common.GetLanguageByCode(language_code);

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

            try
            {

                SubCategories subcategory = _context.SubCategories.Where(s => s.Id == sub_category_id).
                        Where(s => s.IsActive == true).FirstOrDefault();

                SubCategoryLanguages subcategoryLanguages = _context.SubCategoryLanguages.Where(s => s.SubcategoryId == sub_category_id).
                                                                        Where(s => s.LanguageId == language_id).
                                                                        Where(s => s.IsActive == true).
                                                                        FirstOrDefault();


                if (subcategory == null || subcategoryLanguages == null) return (int)Message.NotAllowedToResource;

                //Check : if child exists then cant delete the entry
                List<QuestionCategories> qns = _context.QuestionCategories.Where(q => q.SubCategoryId == sub_category_id).
                                                                                 Where(q => q.IsActive == true).ToList();

                int activeQuestionCount = 0; 
                foreach(QuestionSubCategories qs in qns)
                {
                    //Check if the question of that language is active or not
                    QuestionLanguges activeQnsL = _context.QuestionLanguges.Where(q => q.QuestionId == qs.QuestionId).
                                                            Where(q => q.LanguageId == language_id).
                                                            Where(q => q.IsActive == true).FirstOrDefault();
                    if(activeQnsL != null) activeQuestionCount++;
                }


                if (qns != null && qns.Count > 0 && activeQuestionCount > 0) return (int)Message.NotAllowedToResource;

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

                _context.Entry(subcategoryLanguages).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                _context.SaveChanges();

                return subcategory.Id;
            }
            catch
            {
                return 0;
            }
        }

        #endregion
*/
        #region Tags
        public List<TagViewModel> GetTagsOfTheInstitute(int institute_id, string sortBy, string sortOrder)
        {
            List<TagViewModel> tagList = (from t in _context.Tags
                                          where t.InstituteId == institute_id && t.IsActive == true
                                          select new TagViewModel
                                          {
                                              id = t.Id,
                                              name = t.Name,
                                              last_updated = t.UpdatedOn
                                          }
                         ).ToList();

            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": tagList = tagList.OrderByDescending(a => a.name).ToList(); break;
                        case "UPDATED_ON": tagList = tagList.OrderByDescending(a => a.last_updated).ToList(); break;
                    }

                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": tagList = tagList.OrderBy(a => a.name).ToList(); break;
                        case "UPDATED_ON": tagList = tagList.OrderBy(a => a.last_updated).ToList(); break;
                    }
                }
            }

            return tagList;
        }

        public TagViewModel GetTagOfTheInstitute(int institute_id, int tag_id)
        {
            return _common.GetTagById(institute_id, tag_id);
        }

        public TagViewModel AddTagOfTheInstitute(int institute_id, int user_id, TagAddModel tag)
        {
            try
            {
                _context.Database.BeginTransaction();
                int newId = 0;
                Tags tags = new Tags();
                tags.Name = tag.name;
                tags.InstituteId = institute_id;
                tags.CreatedOn = _common.NowIndianTime();
                tags.UpdatedOn = _common.NowIndianTime();
                tags.CreatedBy = user_id;
                tags.UpdatedBy = user_id;
                tags.IsActive = true;

                _context.Tags.Add(tags);
                _context.SaveChanges();
                newId = tags.Id;

                _context.Database.CommitTransaction();

                TagViewModel tvm = _common.GetTagById(institute_id, newId);

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

        }

        public int AddPlans(int institute_id, int user_id, PlanAddModel newPlan)
        {
            try
            {
                string slug = _common.CreateSlug(newPlan.code);
                Plans oldPlan = _context.Plans.Where(p => p.InstituteId == institute_id && p.IsActive == true &&
                    p.Status == StatusCode.PUBLISHED.ToString() && p.Code == slug).FirstOrDefault();
                if (oldPlan != null)
                    return (int)Message.InvalidInput;

                _context.Database.BeginTransaction();
                int newId = 0;
                Plans plans = new Plans();
                plans.Name = newPlan.name;
                plans.Code = slug;
                plans.Description = newPlan.description;
                plans.InstituteId = institute_id;
                plans.CreatedOn = _common.NowIndianTime();
                plans.UpdatedOn = _common.NowIndianTime();
                plans.CreatedBy = user_id;
                plans.UpdatedBy = user_id;
                plans.IsActive = true;
                plans.PaidExams = newPlan.paid_exams;
                plans.PaidPractices = newPlan.paid_practices;
                plans.InitialPrice = newPlan.initial_price;
                plans.FinalPrice = newPlan.final_price;
                plans.Status = StatusCode.DRAFT.ToString();

                _context.Plans.Add(plans);
                _context.SaveChanges();
                newId = plans.Id;

                _context.Database.CommitTransaction();

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

        public dynamic PublishPlans(int institute_id, int user_id, string plan_code)
        {
            try
            {
                Plans plans = _context.Plans.Where(p => p.InstituteId == institute_id && p.IsActive == true &&
                    p.Status != StatusCode.PUBLISHED.ToString() && p.Code == plan_code).FirstOrDefault();
                if (plans == null)
                    return (int)Message.NotAllowedToResource;

                _context.Database.BeginTransaction();
                plans.UpdatedOn = _common.NowIndianTime();
                plans.UpdatedBy = user_id;
                plans.Status = StatusCode.PUBLISHED.ToString();

                _context.Plans.Update(plans);
                _context.SaveChanges();
                
                _context.Database.CommitTransaction();

                return plans.Code;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return -1;
            }
        }

        public dynamic DeletePlans(int institute_id, int user_id, string plan_code)
        {
            try
            {
                Plans plans = _context.Plans.Where(p => p.InstituteId == institute_id && p.IsActive == true &&
                    p.Code == plan_code).FirstOrDefault();
                if (plans == null)
                    return (int)Message.NotAllowedToResource;

                _context.Database.BeginTransaction();
                plans.UpdatedOn = _common.NowIndianTime();
                plans.UpdatedBy = user_id;
                plans.IsActive = false;

                _context.Plans.Update(plans);
                _context.SaveChanges();

                _context.Database.CommitTransaction();

                return plans.Code;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return -1;
            }
        }


        public List<PlanViewModel> GetPlans(int institute_id, string sortBy, string sortOrder)
        {
            List<PlanViewModel> planList = (from p in _context.Plans
                                          where p.InstituteId == institute_id && p.Status == StatusCode.PUBLISHED.ToString() &&  p.IsActive == true 
                                          select new PlanViewModel
                                          {
                                              code = p.Code,
                                              name = p.Name,
                                              description = p.Description,
                                              paid_exams = (int) p.PaidExams,
                                              paid_practices = (int) p.PaidPractices,
                                              duration_days = (int) p.DurationDays,
                                              initial_price = (int) p.InitialPrice,
                                              final_price = (int) p.FinalPrice,
                                              last_updated = (DateTime) p.UpdatedOn
                                          }
                         ).ToList();

            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": planList = planList.OrderByDescending(a => a.name).ToList(); break;
                        case "UPDATED_ON": planList = planList.OrderByDescending(a => a.last_updated).ToList(); break;
                    }

                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "NAME": planList = planList.OrderBy(a => a.name).ToList(); break;
                        case "UPDATED_ON": planList = planList.OrderBy(a => a.last_updated).ToList(); break;
                    }
                }
            }

            return planList;
        }

        public TagViewModel UpdateTagOfTheInstitute(int institute_id, int user_id, TagEditModel existingTag)
        {
            try
            {

                _context.Database.BeginTransaction();

                int count = 0;

                Tags tags = _context.Tags.Where(t => t.InstituteId == institute_id && t.Id == existingTag.Id && t.IsActive == true).FirstOrDefault();
                if (existingTag.name != null && existingTag.name != tags.Name) { tags.Name = existingTag.name; count++; }

                if(count > 0)
                {
                    tags.UpdatedOn = _common.NowIndianTime();
                    tags.UpdatedBy = user_id;
                }

                _context.Tags.Update(tags);
                _context.SaveChanges();
                
                _context.Database.CommitTransaction();

                TagViewModel tvm = _common.GetTagById(institute_id, existingTag.Id);

                return tvm;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }
        public int DeleteTagOfTheInstitute(int institute_id, int user_id, int tag_id)
        {
            try
            {
                Tags tags = _context.Tags.Where(t => t.Id == tag_id && t.InstituteId == institute_id && t.IsActive == true).FirstOrDefault();

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

                _context.Tags.Update(tags);
                _context.SaveChanges();

                return tag_id;

            }
            catch
            {
                return 0;
            }
        }

        #endregion

        #region Questions
        /*
                //Adding a new question
                public QuestionViewModel AddMultipleChoiceQuestion(int institute_id, int language_id, int user_id, QuestionAddModel q)
                {
                    QuestionType questionType = _common.GetQuestionTypeByCode(QuestionTypeCode.MCQ.ToString());
                    if (questionType == null) return null;
                    int type_id = (int)questionType.Id;

                    if (!(q.status == StatusCode.DRAFT.ToString() || q.status == StatusCode.PUBLISHED.ToString()))
                    {
                        return null;
                    }

                    if (q == null || q.title == null || q.options == null || q.options.Count < 3)
                    {
                        return null;
                    }

                    //Check correct option count
                    int nCorrectOption = 0;
                    for (int i = 0; i < q.options.Count; i++)
                    {
                        if (q.options[i].isCorrect == true)
                            nCorrectOption++;
                    }
                    if (nCorrectOption != 1)
                        return null;


                    if (q.complexity_code > (int)COMPLEXITY.DIFFICULT)
                    {
                        q.complexity_code = (int)COMPLEXITY.DIFFICULT;
                    }
                    else if (q.complexity_code < (int)COMPLEXITY.EASY)
                    {
                        q.complexity_code = (int)COMPLEXITY.EASY;
                    }

                    try
                    {
                        //Step-1: Begin a transaction
                        _context.Database.BeginTransaction();


                        //Step-2: Add the question details
                        Questions questions = new Questions
                        {
                            InstituteId = institute_id,
                            AuthorId = user_id,
                            StatusCode = q.status,
                            ComplexityCode = (short)q.complexity_code,
                            Source = q.source,
                            TypeId = type_id,
                            IsActive = true,
                            CreatedBy = user_id,
                            CreatedOn = _common.NowIndianTime(),
                            UpdatedBy = user_id,
                            UpdatedOn = _common.NowIndianTime()
                        };
                        _context.Questions.Add(questions);
                        _context.SaveChanges();
                        int newQuestionId = questions.Id;

                        //Step-3: Add the question details
                        QuestionLanguges questionLanguges = new QuestionLanguges
                        {
                            QuestionId = newQuestionId,
                            LanguageId = language_id,
                            Question = q.title,
                            Description = q.description,
                            AnswerExplanation = q.answer_explanation,
                            IsActive = true,
                            CreatedBy = user_id,
                            CreatedOn = _common.NowIndianTime(),
                            UpdatedBy = user_id,
                            UpdatedOn = _common.NowIndianTime()
                        };
                        _context.QuestionLanguges.Add(questionLanguges);
                        _context.SaveChanges();


                        //Step-4: Add the option details
                        int newOptionId = 0;
                        int countCorrectOption = 0;
                        foreach (QuestionOptionAddModel o in q.options)
                        {
                            QuestionOptions questionOptions = new QuestionOptions
                            {
                                QuestionId = newQuestionId,

                            };

                            if (o.isCorrect)
                            {
                                questionOptions.IsCorrect = true;
                                countCorrectOption++;
                            }
                            else
                            {
                                questionOptions.IsCorrect = false;
                            }

                            _context.QuestionOptions.Add(questionOptions);
                            _context.SaveChanges();
                            newOptionId = questionOptions.Id;

                            QuestionOptionLanguages questionOptionLanguages = new QuestionOptionLanguages
                            {
                                QuestionId = newQuestionId,
                                QuestionOptionId = newOptionId,
                                LanguageId = language_id,
                                OptionText = o.text,
                                IsActive = true
                            };
                            _context.QuestionOptionLanguages.Add(questionOptionLanguages);
                            _context.SaveChanges();
                        }


                        //Step-5: attach the subtopic to the question
                        if (q.topic_id > 0)
                        {
                            IntegerList qList = new IntegerList();
                            List<int> idl = new List<int>();
                            qList.IdList = idl;
                            idl.Add(newQuestionId);
                            string return_message = string.Empty;
                            AttachCategoryToQuestions(q.topic_id, qList, out return_message);
                        }

                        //Step-6: Attach tags to the question
                        //TODO: attach tags

                        //Step-7: Get the new question infomration and return as response
                        QuestionViewModel qvm = _common.GetQuestionById(institute_id, language_id, newQuestionId);

                        //Step-8: Commit the transaction
                        _context.Database.CommitTransaction();

                        return qvm;

                    }
                    catch (Exception ex)
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }
                }
                */

        
        
        //Adding question option
        public int _QO_addOptions(int language_id, int user_id, int question_id, List<QuestionOptionAddModel> options)
        {
            List<QuestionOptionLanguages> createLanguages = new List<QuestionOptionLanguages>();
            int nCreateLanguage = 0;

            foreach (QuestionOptionAddModel o in options)
            {
                QuestionOptions qo = new QuestionOptions()
                {
                    QuestionId = question_id,
                    IsCorrect = o.isCorrect,
                    CreatedOn = _common.NowIndianTime(),
                    CreatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    IsActive = true
                };
                _context.QuestionOptions.Add(qo);
                _context.SaveChanges();
                int qo_id = qo.Id;

                //<New Option> Add Option Text
                createLanguages.Add(
                new QuestionOptionLanguages()
                {
                    QuestionOptionId = qo_id,
                    LanguageId = language_id,
                    OptionText = o.text,
                    IsActive = true,
                    CreatedOn = _common.NowIndianTime(),
                    CreatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id
                });
                ++nCreateLanguage;
            }
            
            if(nCreateLanguage > 0)
            {
                _context.BulkInsert(createLanguages);
            }
 
            return nCreateLanguage;
        }

        //Check question validity to b4e published
        public QuestionViewModel _QO_validQuestion(int institute_id, int language_id, int question_id)
        {
            QuestionViewModel qvm = _common.GetQuestionById(institute_id, language_id, question_id);

            if (qvm == null) return null;

            if(qvm.type == "SUB" 
                && qvm.options == null)
            {
                return qvm;
            }

            int nCorrect = qvm.options.Where(x => x.isCorrect == true).Count();

            if(qvm.type == "MCQ"
                && qvm.options != null && qvm.options.Count >= 2 && nCorrect == 1)
            {
                return qvm;
            }

            if (qvm.type == "MRQ"
                && qvm.options != null && qvm.options.Count >= 2 && nCorrect >= 1)
            {
                return qvm;
            }

            if (qvm.type == "TNF"
                && qvm.options != null && qvm.options.Count == 2 && nCorrect == 1)
            {
                return qvm;
            }

            return null;
        }



        //Adding a new question
        public QuestionViewModel CloneQuestion(int institute_id, int language_id, int question_id, int user_id, QuestionCloneModel newQuestion)
        {
            //check aleady qns in this lang is present
            int newLanguage_id = GetLanguageIdByCode(newQuestion.language_code);
            if (newLanguage_id <= 0) return null;

            Questions originalQuestion = _context.Questions.Where(q => q.Id == question_id && q.InstituteId == institute_id
            && q.StatusCode == StatusCode.PUBLISHED.ToString() && q.IsActive == true).FirstOrDefault();

            QuestionLanguges originalQuestionLanguage = _context.QuestionLanguges.Where(ql => ql.QuestionId == question_id
            && ql.LanguageId == language_id && ql.IsActive == true).FirstOrDefault();

            QuestionLanguges alreadyExistQuestion = _context.QuestionLanguges.Where(ql => ql.QuestionId == question_id
            && ql.LanguageId == newLanguage_id && ql.IsActive == true).FirstOrDefault();
            
            List<QuestionOptions> originalOption = _context.QuestionOptions.Where(o => o.QuestionId == question_id && o.IsActive == true).ToList();

            if(originalQuestion == null || originalQuestionLanguage == null || alreadyExistQuestion != null)
            {
                return null;
            }

            try
            {
                //Step-1: Begin a transaction
                _context.Database.BeginTransaction();

                //Step-3: Add the question details
                QuestionLanguges questionLanguges = new QuestionLanguges
                {
                    QuestionId = question_id,
                    LanguageId = newLanguage_id,
                    Question = newQuestion.title,
                    AnswerExplanation = newQuestion.answer_explanation,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.QuestionLanguges.Add(questionLanguges);
                _context.SaveChanges();


                //Step-4: Add the option details
                Dictionary<int, string> d = new Dictionary<int, string>();
                for (int i = 0; i < newQuestion.options.Count; i++)
                {
                    d.Add(newQuestion.options[i].id, newQuestion.options[i].text);
                }


                foreach (QuestionOptions option in originalOption)
                {
                    QuestionOptionLanguages alreadyOptionLanguageExist = _context.QuestionOptionLanguages.Where(qol => qol.QuestionOptionId == option.Id
                    && qol.LanguageId == newLanguage_id && qol.IsActive == true).FirstOrDefault();
                    bool validOption = d.ContainsKey(option.Id); //it should be true

                    if(alreadyOptionLanguageExist != null || validOption == false)
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }

                    QuestionOptionLanguages questionOptionLanguages = new QuestionOptionLanguages
                    {
                        QuestionId = question_id,
                        QuestionOptionId = option.Id,
                        LanguageId = newLanguage_id,
                        OptionText = d[option.Id],
                        IsActive = true
                    };
                    _context.QuestionOptionLanguages.Add(questionOptionLanguages);
                    _context.SaveChanges();
                }

                //Step-7: Commit the transaction
                _context.Database.CommitTransaction();

                //Step-8: Get the new question infomration and return as response
                QuestionViewModel qvm = _common.GetQuestionById(institute_id, newLanguage_id, question_id);

                return qvm;

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

        //Adding a new question
        public QuestionViewModel AddMultipleChoiceQuestion(int institute_id, int language_id, int user_id, QuestionAddModel q)
        {
            QuestionType questionType = _common.GetQuestionTypeByCode(QuestionTypeCode.MCQ.ToString());
             if (questionType == null) return null;
            int type_id = (int)questionType.Id;

            if (q == null || q.title == null)
            {
                return null;
            }

            if (!(q.status == StatusCode.DRAFT.ToString() || q.status == StatusCode.PUBLISHED.ToString()))
            {
                return null;
            }

            //Check correct option count
            if (q.status == StatusCode.PUBLISHED.ToString())
            {
                if (q.options == null || q.options.Count == 0) return null;

                int nCorrectOption = q.options.Where(x => x.isCorrect == true).Count();
                if (nCorrectOption != 1)
                    return null;
            }            

            q.complexity_code = _common._calculateComplexity(q.complexity_code);

            try
            {
                //Step-1: Begin a transaction
                _context.Database.BeginTransaction();

                //Step-2: Add the question details
                Questions questions = new Questions
                {
                    InstituteId = institute_id,
                    AuthorId = user_id,
                    StatusCode = q.status,
                    ComplexityCode = (short)q.complexity_code,
                    Source = q.source,
                    TypeId = type_id,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.Questions.Add(questions);
                _context.SaveChanges();
                int newQuestionId = questions.Id;

                //Step-3: Add the question details
                QuestionLanguges questionLanguges = new QuestionLanguges
                {
                    QuestionId = newQuestionId,
                    LanguageId = language_id,
                    Question = q.title,
                    Description = q.description,
                    AnswerExplanation = q.answer_explanation,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.QuestionLanguges.Add(questionLanguges);
                _context.SaveChanges();

                //Step-4: Add the option details
                if (q.options != null && q.options.Count > 0)
                {
                    if (_QO_addOptions(language_id, user_id, newQuestionId, q.options) == 0)
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }
                }
                else if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                //Step-5: Commit the transaction
                _context.Database.CommitTransaction();

                //Step-6: attach the topic to the question
                if (q.topic_id > 0)
                {
                    IntegerList qList = new IntegerList();
                    List<int> idl = new List<int>();
                    qList.IdList = idl;
                    idl.Add(newQuestionId);
                    string return_message = string.Empty;
                    AttachCategoryToQuestions(q.topic_id, qList, out return_message);
                }

                //Step-7: Attach tags to the question
                //TODO: attach tags

                //Step-8: Get the new question infomration and return as response
                QuestionViewModel qvm;
                if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    qvm = _QO_validQuestion(institute_id, language_id, newQuestionId);
                    if (qvm == null) _context.Database.RollbackTransaction();
                    return qvm;
                }
                else
                    qvm = _common.GetQuestionById(institute_id, language_id, newQuestionId);

                
                return qvm;

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

        public QuestionViewModel AddMultipleResposeQuestion(int institute_id, int language_id, int user_id, QuestionAddModel q)
        {
            QuestionType questionType = _common.GetQuestionTypeByCode(QuestionTypeCode.MRQ.ToString());
            if (questionType == null) return null;
            int type_id = (int)questionType.Id;

            if (q == null || q.title == null)
            {
                return null;
            }

            if (!(q.status == StatusCode.DRAFT.ToString() || q.status == StatusCode.PUBLISHED.ToString()))
            {
                return null;
            }

            //Check correct option count
            if (q.status == StatusCode.PUBLISHED.ToString())
            {
                if (q.options == null || q.options.Count == 0) return null;
                int nCorrectOption = q.options.Where(x => x.isCorrect == true).Count();
                if (nCorrectOption < 1)
                    return null;
            }
                
            q.complexity_code = _common._calculateComplexity(q.complexity_code);

            try
            {
                //Step-1: Begin a transaction
                _context.Database.BeginTransaction();


                //Step-2: Add the question details
                Questions questions = new Questions
                {
                    InstituteId = institute_id,
                    AuthorId = user_id,
                    StatusCode = q.status,
                    ComplexityCode = (short)q.complexity_code,
                    Source = q.source,
                    TypeId = type_id,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.Questions.Add(questions);
                _context.SaveChanges();
                int newQuestionId = questions.Id;

                //Step-3: Add the question details
                QuestionLanguges questionLanguges = new QuestionLanguges
                {
                    QuestionId = newQuestionId,
                    LanguageId = language_id,
                    Question = q.title,
                    Description = q.description,
                    AnswerExplanation = q.answer_explanation,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.QuestionLanguges.Add(questionLanguges);
                _context.SaveChanges();


                //Step-4: Add the option details
                if (q.options != null && q.options.Count > 0)
                {
                    if (_QO_addOptions(language_id, user_id, newQuestionId, q.options) == 0)
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }
                } else if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                //Step-5: Commit the transaction
                _context.Database.CommitTransaction();

                //Step-6: attach the subtopic to the question
                if (q.topic_id > 0)
                {
                    IntegerList qList = new IntegerList();
                    List<int> idl = new List<int>();
                    qList.IdList = idl;
                    idl.Add(newQuestionId);
                    string return_message = string.Empty;
                    AttachCategoryToQuestions(q.topic_id, qList, out return_message);
                }

                //Step-7: Attach tags to the question
                //TODO: attach tags

                //Step-8: Get the new question infomration and return as response
                QuestionViewModel qvm;
                if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    qvm = _QO_validQuestion(institute_id, language_id, newQuestionId);
                    if (qvm == null) _context.Database.RollbackTransaction();
                    return qvm;
                }
                else
                    qvm = _common.GetQuestionById(institute_id, language_id, newQuestionId);

                
                return qvm;
            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        public QuestionViewModel AddTrueFalseQuestion(int institute_id, int language_id, int user_id, QuestionAddModel q)
        {
            QuestionType questionType = _common.GetQuestionTypeByCode(QuestionTypeCode.TNF.ToString());
            if (questionType == null) return null;
            int type_id = (int)questionType.Id;

            if (q == null || q.title == null)
            {
                return null;
            }

            if (!(q.status == StatusCode.DRAFT.ToString() || q.status == StatusCode.PUBLISHED.ToString()))
            {
                return null;
            }

            //Check 2 options should be there
            if (q.options.Count() != 2)
                return null;

            //Check options should be true and false
            int nTrue = q.options.Where(x => x.text.Equals("true", StringComparison.CurrentCultureIgnoreCase)).Count();
            int nFalse = q.options.Where(x => x.text.Equals("true", StringComparison.CurrentCultureIgnoreCase)).Count();
            if (nTrue != 1 || nFalse != 1)
                return null;

            //Check correct option count
            int nCorrectOption = q.options.Where(x => x.isCorrect == true).Count();
            if (nCorrectOption != 1)
                return null;

            q.complexity_code = _common._calculateComplexity(q.complexity_code);

            try
            {
                //Step-1: Begin a transaction
                _context.Database.BeginTransaction();


                //Step-2: Add the question details
                Questions questions = new Questions
                {
                    InstituteId = institute_id,
                    AuthorId = user_id,
                    StatusCode = q.status,
                    ComplexityCode = (short)q.complexity_code,
                    Source = q.source,
                    TypeId = type_id,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.Questions.Add(questions);
                _context.SaveChanges();
                int newQuestionId = questions.Id;

                //Step-3: Add the question details
                QuestionLanguges questionLanguges = new QuestionLanguges
                {
                    QuestionId = newQuestionId,
                    LanguageId = language_id,
                    Question = q.title,
                    Description = q.description,
                    AnswerExplanation = q.answer_explanation,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.QuestionLanguges.Add(questionLanguges);
                _context.SaveChanges();

                //Step-4: Add the option details
                if (q.options != null && q.options.Count > 0)
                {
                    if (_QO_addOptions(language_id, user_id, newQuestionId, q.options) == 0)
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }
                }
                else if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    _context.Database.RollbackTransaction();
                    return null;
                }

                //Step-5: Commit the transaction
                _context.Database.CommitTransaction();

                //Step-6: attach the subtopic to the question
                if (q.topic_id > 0)
                {
                    IntegerList qList = new IntegerList();
                    List<int> idl = new List<int>();
                    qList.IdList = idl;
                    idl.Add(newQuestionId);
                    string return_message = string.Empty;
                    AttachCategoryToQuestions(q.topic_id, qList, out return_message);
                }

                //Step-7: Attach tags to the question
                //TODO: attach tags
                
                //Step-8: Get the new question infomration and return as response
                QuestionViewModel qvm;
                if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    qvm = _QO_validQuestion(institute_id, language_id, newQuestionId);
                    if (qvm == null) _context.Database.RollbackTransaction();
                    return qvm;
                }
                else
                    qvm = _common.GetQuestionById(institute_id, language_id, newQuestionId);

                
                return qvm;
            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        public QuestionViewModel AddSubjectiveQuestion(int institute_id, int language_id, int user_id, QuestionAddModel q)
        {
            QuestionType questionType = _common.GetQuestionTypeByCode(QuestionTypeCode.SUB.ToString());
            if (questionType == null) return null;

            int type_id = (int)questionType.Id;
            if (q == null || q.title == null || q.options != null)
            {
                return null;
            }

            if (!(q.status == StatusCode.DRAFT.ToString() || q.status == StatusCode.PUBLISHED.ToString()))
            {
                return null;
            }

            q.complexity_code = _common._calculateComplexity(q.complexity_code);

            try
            {
                //Step-1: Begin a transaction
                _context.Database.BeginTransaction();

                //Step-2: Add the question details
                Questions questions = new Questions
                {
                    InstituteId = institute_id,
                    AuthorId = user_id,
                    StatusCode = q.status,
                    ComplexityCode = (short)q.complexity_code,
                    Source = q.source,
                    TypeId = type_id,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.Questions.Add(questions);
                _context.SaveChanges();
                int newQuestionId = questions.Id;

                //Step-3: Add the question details
                QuestionLanguges questionLanguges = new QuestionLanguges
                {
                    QuestionId = newQuestionId,
                    LanguageId = language_id,
                    Question = q.title,
                    Description = q.description,
                    AnswerExplanation = q.answer_explanation,
                    IsActive = true,
                    CreatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedBy = user_id,
                    UpdatedOn = _common.NowIndianTime()
                };
                _context.QuestionLanguges.Add(questionLanguges);
                _context.SaveChanges();

                //Step-4: Commit the transaction
                _context.Database.CommitTransaction();

                //Step-5: attach the subtopic to the question
                if (q.topic_id > 0)
                {
                    IntegerList qList = new IntegerList();
                    List<int> idl = new List<int>();
                    qList.IdList = idl;
                    idl.Add(newQuestionId);
                    string return_message = string.Empty;
                    AttachCategoryToQuestions(q.topic_id, qList, out return_message);
                }

                //Step-6: Attach tags to the question
                //TODO: attach tags

                //Step-7: Get the new question infomration and return as response
                QuestionViewModel qvm;
                if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    qvm = _QO_validQuestion(institute_id, language_id, newQuestionId);
                    if (qvm == null) _context.Database.RollbackTransaction();
                    return qvm;
                }
                else
                    qvm = _common.GetQuestionById(institute_id, language_id, newQuestionId);


                return qvm;


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

        //Update a question
        public QuestionViewModel UpdateQuestion(int institute_id, int language_id, int user_id, QuestionEditModel q)
        {
            try
            {
                _context.Database.BeginTransaction();

                //get question to be updated
                Questions questions = _context.Questions.Where(x => x.Id == q.id && x.InstituteId == institute_id 
                                        && x.StatusCode == StatusCode.DRAFT.ToString() && x.IsActive == true).FirstOrDefault();

                if (questions == null) return null;
                
                //update question
                int count = 0;
                if (q.author_id > 0 && questions.AuthorId != q.author_id) { questions.AuthorId = q.author_id; count++; }
                if (q.complexity_code > 0 && questions.ComplexityCode != q.complexity_code) { questions.ComplexityCode = (short)q.complexity_code; count++; }
                if (q.source != null && questions.Source != q.source) { questions.Source = q.source; count++; }
                
                if(count > 0)
                {
                    questions.UpdatedBy = user_id;
                    questions.UpdatedOn = _common.NowIndianTime();
                    _context.Questions.Update(questions);
                    _context.SaveChanges();
                }                
                
                //update question language
                count = 0;
                QuestionLanguges questionLanguges = _context.QuestionLanguges.Where(ql => ql.QuestionId == q.id).FirstOrDefault();
                if (q.title != null && questionLanguges.Question != q.title) { questionLanguges.Question = q.title; count++; }
                if (q.answer_explanation != null && questionLanguges.AnswerExplanation != q.answer_explanation) { questionLanguges.AnswerExplanation = q.answer_explanation; count++; }

                if (count > 0)
                {
                    questionLanguges.UpdatedBy = user_id;
                    questionLanguges.UpdatedOn = _common.NowIndianTime();
                    _context.QuestionLanguges.Update(questionLanguges);
                    _context.SaveChanges();
                }

                if (q.options != null && q.options.Count > 0)
                {
                    List<QuestionOptions> allOptions = _context.QuestionOptions.Where(ao => ao.QuestionId == q.id && ao.IsActive == true).ToList();
                    
                    //Delete the extra options
                    List<int> allOptionIds = allOptions.Select(x => x.Id).ToList();
                    List<int> newOptionIds = q.options.Select(x => x.id).ToList();
                    List<int> deleteOptionIds = allOptionIds.Except(newOptionIds).ToList();
                    List<QuestionOptions> deleteOptionList = new List<QuestionOptions>();

                    if (deleteOptionIds != null)
                    {
                        for (int i = 0; i < deleteOptionIds.Count; i++)
                        {
                            QuestionOptions deleteOption = _context.QuestionOptions.Where(x => x.QuestionId == q.id && x.IsActive == true
                                                            && x.Id == deleteOptionIds[i]).FirstOrDefault();

                            deleteOption.IsActive = false;
                            deleteOptionList.Add(deleteOption);
                        }
                    }
                    _context.BulkUpdate(deleteOptionList);
                    _context.SaveChanges();

                    Dictionary<int, QuestionOptions> d = new Dictionary<int, QuestionOptions>();
                    List<int> idList = new List<int>();
                    for (int i = 0; i < allOptions.Count; i++)
                    {
                        d.Add(allOptions[i].Id, allOptions[i]);
                        idList.Add(allOptions[i].Id);
                    }

                    List<QuestionOptions> updates = new List<QuestionOptions>();
                    List<QuestionOptionLanguages> updateLanguages = new List<QuestionOptionLanguages>();
                    List<QuestionOptionLanguages> createLanguages = new List<QuestionOptionLanguages>();
                    int nUpdate = 0;
                    int nUpdateLanguage = 0;
                    int nCreateLanguage = 0;

                    foreach (QuestionOptionEditModel o in q.options)
                    {
                        //check if option is already there ?
                        if (d.Count == 0 || !d.ContainsKey(o.id))
                        {
                           //<New option> create an option
                           QuestionOptions qo = new QuestionOptions()
                                     {
                                        QuestionId = q.id,
                                        IsCorrect = o.isCorrect,
                                        CreatedOn = _common.NowIndianTime(),
                                        CreatedBy = user_id,
                                        UpdatedOn = _common.NowIndianTime(),
                                        UpdatedBy = user_id,
                                        IsActive = true
                                    };

                            _context.QuestionOptions.Add(qo);
                            _context.SaveChanges();
                            int qo_id = qo.Id;

                            //<New Option> Add Option Text
                            createLanguages.Add(
                                new QuestionOptionLanguages()
                                {
                                    QuestionOptionId = qo_id,
                                    LanguageId = language_id,
                                    OptionText = o.text,
                                    IsActive = true,
                                    CreatedOn = _common.NowIndianTime(),
                                    CreatedBy = user_id,
                                    UpdatedOn = _common.NowIndianTime(),
                                    UpdatedBy = user_id
                                });
                            ++nCreateLanguage;
                        }
                        else 
                        {
                            //<Existing option update> update options

                            QuestionOptions updateOption= allOptions.Where(f => f.Id == o.id).FirstOrDefault();
                            if (updateOption == null) continue;

                            if(updateOption.IsCorrect != o.isCorrect)
                            {
                                updateOption.IsCorrect = o.isCorrect;
                                updates.Add(updateOption);
                                nUpdate++;
                            }
                            
                            QuestionOptionLanguages qol = _context.QuestionOptionLanguages.Where(x => x.QuestionOptionId == o.id && x.LanguageId == language_id && x.IsActive == true).FirstOrDefault();
                            
                            if(qol != null)
                            {
                                qol.OptionText = o.text;
                                qol.UpdatedBy = user_id;
                                qol.UpdatedOn = _common.NowIndianTime();
                                updateLanguages.Add(qol);
                                ++nUpdateLanguage;
                            }
                            
                        }
                    }

                    if (nCreateLanguage > 0)
                    {
                        _context.BulkInsert(createLanguages);
                    }

                    if (nUpdate > 0)
                    {
                        _context.BulkUpdate(updates);
                    }

                    if (nUpdateLanguage > 0)
                    {
                        _context.BulkUpdate(updateLanguages);
                    }

                    //TODO: fix this: while updating a question, if we leave the option as blank array and update, the correct answer option changes to 0
                    //TODO: after db change effect -> questions.AnswerOptionId = correctOptionId;
                    //TODO: after db change effect -> _context.Questions.Update(questions);
                    //TODO: after db change effect -> _context.SaveChanges();
                }

                
                //Step-6: Get the new question infomration and return as response
                QuestionViewModel qvm;
                if (q.status == StatusCode.PUBLISHED.ToString())
                {
                    qvm = _QO_validQuestion(institute_id, language_id, q.id);
                    if (qvm != null)
                    {
                        questions.StatusCode = StatusCode.PUBLISHED.ToString();
                        _context.Questions.Update(questions);
                        _context.SaveChanges();
                    }
                    
                }

                //Step-7: Commit the transaction
                _context.Database.CommitTransaction();


                qvm = _common.GetQuestionById(institute_id, language_id, q.id);

                return qvm;
            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return null;
            }

        }

        public int DeleteQuestion(int institute_id, int user_id, int author_id, int question_id)
        {
            int return_value;
            
            try
            {
                Questions questions = _context.Questions.Where(q => q.Id == question_id && q.InstituteId == institute_id && q.IsActive == true).FirstOrDefault();
                if (questions == null) return -1;
                if (author_id > 0 && questions.CreatedBy != author_id) return -1;
                
                questions.IsActive = false;
                questions.UpdatedOn = _common.NowIndianTime();
                questions.UpdatedBy = user_id;
                _context.Questions.Update(questions);
                _context.SaveChanges();

                return_value = question_id;
            }
            catch
            {
                return_value = -1;
            }
            return return_value;
        }

        public int DeleteQuestionsList(int institute_id, int language_id, int user_id, int author_id, IntegerList questionIdList, out string return_message)
        {
            int return_value = 0;
            
            try
            {
                List<Questions> questions = _context.Questions.Where(q => q.InstituteId == institute_id 
                                                    && questionIdList.IdList.Contains(q.Id) && q.IsActive == true).ToList();

                if (questions == null)
                {
                    return_message = string.Format("couldn't delete questions.", return_value);
                    return -1;
                }

                if (author_id > 0)
                {
                    List<Questions> otherQns = questions.Where(q => q.CreatedBy != author_id).ToList();
                    if (otherQns != null && otherQns.Count > 0)
                    {
                        return_message = string.Format("couldn't delete questions.", return_value);
                        return -1;
                    }
                }


                questions.Select(q => { q.IsActive = false; return q; }).ToList();
                questions.Select(q => { q.UpdatedOn = _common.NowIndianTime(); return q; }).ToList();
                questions.Select(q => { q.UpdatedBy = user_id; return q; }).ToList();
                _context.BulkUpdate(questions);
                _context.SaveChanges();

                return_value = questions.Count();
                return_message = string.Format("{0} questions deleted.", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }

            return return_value;
        }

        /*
        //Getting all questions of an institute
        public List<QuestionViewAllModel> GetAllQuestionsOfTheClass(int institute_id, int user_id, int language_id, int class_id)
        {
            ClassViewModel cls = GetClassByID(institute_id, language_id, class_id);
            if (cls == null) return null;

            DateTime first = _common.NowIndianTime();

            List<SubjectViewModel> subjectList = GetSubjectsOfTheClass(institute_id, language_id, class_id, null, null);
            if (subjectList == null || subjectList.Count == 0) return null;


            TimeSpan second = _common.NowIndianTime() - first;

            List<int> subidList = new List<int>();
            for (int i = 0; i < subjectList.Count; i++)
            {
                subidList.Add(subjectList[i].Id);
            }

            TimeSpan third = _common.NowIndianTime() - first;

            List<QuestionViewAllModel> qvam = (from q in _context.Questions
                                               join ql in _context.QuestionLanguges on q.Id equals ql.QuestionId
                                               join qt in _context.QuestionTypes on q.TypeId equals qt.Id
                                               join sq in _context.QuestionSubCategories on q.Id equals sq.QuestionId
                                               join sc in _context.SubCategories on sq.SubCategoryId equals sc.Id
                                               join scl in _context.SubCategoryLanguages on sc.Id equals scl.SubcategoryId
                                               join c in _context.Categories on sc.CategoryId equals c.Id
                                               join cl in _context.CategoryLanguages on c.Id equals cl.CategoryId
                                               join sub in _context.Subjects on c.SubjectId equals sub.Id
                                               join subl in _context.SubjectLanguages on sub.Id equals subl.SubjectId
                                               
                                               where subidList.Contains(sub.Id)
                                                          && scl.IsActive == true && scl.LanguageId == language_id
                                                          && cl.IsActive == true && cl.LanguageId == language_id
                                                          && subl.IsActive == true && subl.LanguageId == language_id
                                                          && q.InstituteId == institute_id
                                                          && ql.LanguageId == language_id && ql.IsActive == true
                                                          && qt.IsActive == true
                                                          
                                                         
                                                          
                                               select new QuestionViewAllModel
                                               {
                                                   id = q.Id,
                                                   title = ql.Question,
                                                   author = q.AuthorId,
                                                   complexity_code = q.ComplexityCode,
                                                   source = q.Source,
                                                   type = qt.Code,
                                                   type_name = qt.Name,
                                                   status = q.StatusCode,                                                   
                                                   isActive = ql.IsActive,
                                                   topic_id = c.Id,
                                                   topic_name = cl.Name,
                                                   subtopic_id = sc.Id,
                                                   subtopic_name = scl.Name                                                   
                                               }
                                     ).ToList();

            TimeSpan fourth = _common.NowIndianTime() - first;
            
            foreach (QuestionViewAllModel question in qvam)
            {
                BookmarkedQuestions bs = _common.GetBookmarkedQuestion(user_id, question.id);

                if (bs != null)
                    question.isBookmarked = true;
                else
                    question.isBookmarked = false;               
            }
            
            TimeSpan fifth = _common.NowIndianTime() - first;

            return qvam;
        }
        */

        
        //alternaative approach
        public List<QuestionViewAllModel> GetAllQuestionsOfTheClass(int institute_id, int user_id, int language_id, int class_id)
        {
            ClassViewModel cvm = GetClassByID(institute_id, class_id);
            if (cvm == null) return null;

  
            List<QuestionViewAllModel> qvam = (from q in _context.Questions
                                               join ql in _context.QuestionLanguges on q.Id equals ql.QuestionId
                                               join qt in _context.QuestionTypes on q.TypeId equals qt.Id
                                               join qc in _context.QuestionCategories on q.Id equals qc.QuestionId
                                               join c in _context.Categories on qc.CategoryId equals c.Id
                                               join sub in _context.Subjects on c.SubjectId equals sub.Id
                                               join cls in _context.Classes on sub.ClassId equals cls.Id
                                               
                                               where cls.Id == cvm.id     
                                                          && q.InstituteId == institute_id && q.IsActive == true
                                                          && ql.LanguageId == language_id && ql.IsActive == true
                                                          && qt.IsActive == true
                                                          && cls.Id == class_id && cls.IsActive == true


                                               select new QuestionViewAllModel
                                               {
                                                   id = q.Id,
                                                   title = ql.Question,
                                                   author = q.AuthorId,
                                                   complexity_code = q.ComplexityCode,
                                                   source = q.Source,
                                                   type = qt.Code,
                                                   type_name = qt.Name,
                                                   status = q.StatusCode,
                                                   isActive = ql.IsActive,
                                                   topic_id = c.Id,
                                                   topic_name = c.Name,
                                                   isBookmarked = 
                                                            _context.BookmarkedQuestions.
                                                            Where(b => b.UserId == user_id).
                                                            Where(b => b.QuestionId == q.Id).FirstOrDefault().IsActive,
                                                   languages_available = _context.QuestionLanguges.
                                                            Where(l => l.QuestionId == q.Id && l.IsActive == true).Select(l => l.LanguageId).ToList()
                                               }
                                     ).ToList();


        
            return qvam;
        }
        


        //Getting all questions of an institute
        public List<QuestionViewAllModel> GetAllQuestionOfCategory(int institute_id, int user_id, int language_id, int category_id)
        {
            CategoryViewModel cat = GetCategoryByID(institute_id, language_id, category_id);
            if (cat == null) return null;

            List<QuestionViewAllModel> qvam = (from q in _context.Questions
                                               join ql in _context.QuestionLanguges on q.Id equals ql.QuestionId
                                               join qt in _context.QuestionTypes on q.TypeId equals qt.Id
                                               join qc in _context.QuestionCategories on q.Id equals qc.QuestionId
                                               join c in _context.Categories on qc.CategoryId equals c.Id
                                               join sub in _context.Subjects on c.SubjectId equals sub.Id
                                               join cls in _context.Classes on sub.ClassId equals cls.Id

                                               where c.Id == category_id
                                                          && q.InstituteId == institute_id && q.IsActive == true
                                                          && ql.LanguageId == language_id && ql.IsActive == true
                                                          && qt.IsActive == true
                                                          && cls.IsActive == true


                                               select new QuestionViewAllModel
                                               {
                                                   id = q.Id,
                                                   title = ql.Question,
                                                   author = q.AuthorId,
                                                   complexity_code = q.ComplexityCode,
                                                   source = q.Source,
                                                   type = qt.Code,
                                                   type_name = qt.Name,
                                                   status = q.StatusCode,
                                                   isActive = ql.IsActive,
                                                   topic_id = c.Id,
                                                   topic_name = c.Name,
                                                   isBookmarked =
                                                            _context.BookmarkedQuestions.
                                                            Where(b => b.UserId == user_id).
                                                            Where(b => b.QuestionId == q.Id).FirstOrDefault().IsActive,
                                                   languages_available = _context.QuestionLanguges.
                                                            Where(l => l.QuestionId == q.Id && l.IsActive == true).Select(l => l.LanguageId).ToList()
                                               }
                                     ).ToList();



            return qvam;
        }
/*
        //Getting all questions of an institute
        public List<QuestionViewAllModel> GetAllQuestionOfSubCategory(int institute_id, int user_id, int language_id, int subcategory_id)
        {
            SubCategoryViewModel subcat = GetSubCategoryByID(institute_id, language_id, subcategory_id);
            if (subcat == null) return null;

            List<QuestionViewAllModel> qvam = (from q in _context.Questions
                                               join ql in _context.QuestionLanguges on q.Id equals ql.QuestionId
                                               join qt in _context.QuestionTypes on q.TypeId equals qt.Id
                                               join sq in _context.QuestionSubCategories on q.Id equals sq.QuestionId
                                               join sc in _context.SubCategories on sq.SubCategoryId equals sc.Id
                                               join c in _context.Categories on sc.CategoryId equals c.Id

                                               where sq.SubCategoryId == subcat.Id
                                                          && ql.LanguageId == language_id && ql.IsActive == true
                                                          && qt.IsActive == true
                                               select new QuestionViewAllModel
                                               {
                                                   id = q.Id,
                                                   title = ql.Question,
                                                   author = q.AuthorId,
                                                   complexity_code = q.ComplexityCode,
                                                   source = q.Source,
                                                   type = qt.Code,
                                                   type_name = qt.Name,
                                                   status = q.StatusCode,
                                                   isActive = ql.IsActive,
                                                   topic_id = c.Id,
                                                   topic_name = c.Name,
                                                   subtopic_id = subcat.Id,
                                                   subtopic_name = subcat.Name
                                               }
                                     ).ToList();

            foreach (QuestionViewAllModel question in qvam)
            {
                BookmarkedQuestions bs = _common.GetBookmarkedQuestion(user_id, question.id);

                if (bs != null)
                    question.isBookmarked = true;
                else
                    question.isBookmarked = false;
            }

            return qvam;
        }
*/

        //Getting all questions of an institute
        public List<QuestionViewAllModel> GetAllQuestionsOfTheSubject(int institute_id, int user_id, int language_id, int subject_id)
        {
            SubjectViewModel subject = GetSubjectById(institute_id, subject_id);
            if (subject == null) return null;
            
            List<QuestionViewAllModel> qvam = (from q in _context.Questions
                                               join ql in _context.QuestionLanguges on q.Id equals ql.QuestionId
                                               join qt in _context.QuestionTypes on q.TypeId equals qt.Id
                                               join qc in _context.QuestionCategories on q.Id equals qc.QuestionId
                                               join c in _context.Categories on qc.CategoryId equals c.Id
                                               join sub in _context.Subjects on c.SubjectId equals sub.Id
                                               join cls in _context.Classes on sub.ClassId equals cls.Id

                                               where sub.Id == subject.id
                                                          && q.InstituteId == institute_id && q.IsActive == true
                                                          && ql.LanguageId == language_id && ql.IsActive == true
                                                          && qt.IsActive == true
                                                          && cls.IsActive == true


                                               select new QuestionViewAllModel
                                               {
                                                   id = q.Id,
                                                   title = ql.Question,
                                                   author = q.AuthorId,
                                                   complexity_code = q.ComplexityCode,
                                                   source = q.Source,
                                                   type = qt.Code,
                                                   type_name = qt.Name,
                                                   status = q.StatusCode,
                                                   isActive = ql.IsActive,
                                                   topic_id = c.Id,
                                                   topic_name = c.Name,
                                                   isBookmarked =
                                                            _context.BookmarkedQuestions.
                                                            Where(b => b.UserId == user_id).
                                                            Where(b => b.QuestionId == q.Id).FirstOrDefault().IsActive,
                                                   languages_available = _context.QuestionLanguges.
                                                            Where(l => l.QuestionId == q.Id && l.IsActive == true).Select(l => l.LanguageId).ToList()
                                               }
                                     ).ToList();



            return qvam;
        }

        //Getting all questions of an institute
        public List<QuestionViewAllModel> GetAllQuestionsOfClass(int institute_id, int user_id, int language_id, 
                                int class_id, string type, string module, int module_id, 
                                int complexity, int author_id, int translation_missing_id, string sortBy, string sortOrder)
        {
            List<QuestionViewAllModel> qnsList = new List<QuestionViewAllModel>();
            
            switch (module.ToUpper())
            {
                case "CLASS":
                    qnsList = GetAllQuestionsOfTheClass(institute_id, user_id, language_id, module_id);
                    break;

                case "SUBJECT":
                    qnsList = GetAllQuestionsOfTheSubject(institute_id, user_id, language_id, module_id);
                    break;

                case "CATEGORY":
                    qnsList = GetAllQuestionOfCategory(institute_id, user_id, language_id, module_id);
                    break;

            }

            qnsList = qnsList.Where(q => q.status.ToUpper() == StatusCode.PUBLISHED.ToString()).ToList();

            if (qnsList != null && qnsList.Count > 0 && type != null)
            {
                qnsList = qnsList.Where(q => q.type.ToUpper() == type.ToUpper()).ToList();
            }

            if (qnsList != null && qnsList.Count > 0 && author_id != null && author_id > 0)
            {
                qnsList = qnsList.Where(q => q.author == author_id).ToList();
            }

            if (qnsList != null && qnsList.Count > 0 && complexity != null && complexity > 0)
            {
                qnsList = qnsList.Where(q => q.complexity_code == complexity).ToList();
            }

            if (qnsList != null && qnsList.Count > 0 && translation_missing_id != null && translation_missing_id > 0)
            {
                qnsList = qnsList.Where(q => q.languages_available.Contains(translation_missing_id) == false).ToList();
            }

            return qnsList;
        }

        //Getting all draft questions of an institute
        public List<QuestionViewAllModel> GetAllDraftQuestionsOfClass(int institute_id, int user_id, int language_id,
                                int class_id, string type, string module, int module_id,
                                int complexity, int author_id, string sortBy, string sortOrder)
        {
            List<QuestionViewAllModel> qnsList = new List<QuestionViewAllModel>();

            switch (module.ToUpper())
            {
                case "CLASS":
                    qnsList = GetAllQuestionsOfTheClass(institute_id, user_id, language_id, module_id);
                    break;

                case "SUBJECT":
                    qnsList = GetAllQuestionsOfTheSubject(institute_id, user_id, language_id, module_id);
                    break;

                case "CATEGORY":
                    qnsList = GetAllQuestionOfCategory(institute_id, user_id, language_id, module_id);
                    break;

            }

            if (qnsList == null || qnsList.Count == 0) return qnsList;
            
            qnsList = qnsList.Where(q => q.status.ToUpper() == StatusCode.DRAFT.ToString()).ToList();

            if (qnsList != null && qnsList.Count > 0 && author_id != null && author_id > 0)
            {
                qnsList = qnsList.Where(q => q.author == author_id).ToList();
            }

            if (qnsList != null && qnsList.Count > 0 && type != null)
            {
                qnsList = qnsList.Where(q => q.type.ToUpper() == type.ToUpper()).ToList();
            }

            if (qnsList != null && qnsList.Count > 0 && complexity != null && complexity > 0)
            {
                qnsList = qnsList.Where(q => q.complexity_code == complexity).ToList();
            }

            return qnsList;
        }


        //Getting all bookmarked questions of an institute
        public List<QuestionViewAllModel> GetAllBookmarkedQuestionsOfClass(int institute_id, int user_id, int language_id,
                                int class_id, string type, string module, int module_id,
                                int complexity, int translation_missing_id ,string sortBy, string sortOrder)
        {
            List<QuestionViewAllModel> qnsList = new List<QuestionViewAllModel>();

            switch (module.ToUpper())
            {
                case "CLASS":
                    qnsList = GetAllQuestionsOfTheClass(institute_id, user_id, language_id, module_id);
                    break;

                case "SUBJECT":
                    qnsList = GetAllQuestionsOfTheSubject(institute_id, user_id, language_id, module_id);
                    break;

                case "CATEGORY":
                    qnsList = GetAllQuestionOfCategory(institute_id, user_id, language_id, module_id);
                    break;

            }

            qnsList = qnsList.Where(q => q.isBookmarked == true).ToList();
            qnsList = qnsList.Where(q => q.status.ToUpper() == StatusCode.PUBLISHED.ToString()).ToList();

            if (type != null)
            {
                qnsList = qnsList.Where(q => q.type.ToUpper() == type.ToUpper()).ToList();
            }

            if (complexity != null && complexity > 0)
            {
                qnsList = qnsList.Where(q => q.complexity_code == complexity).ToList();
            }

            if (qnsList != null && qnsList.Count > 0 && translation_missing_id != null && translation_missing_id > 0)
            {
                qnsList = qnsList.Where(q => q.languages_available.Contains(translation_missing_id) == false).ToList();
            }

            return qnsList;
        }


        //Getting a specific question
        public QuestionViewModel GetQuestionById(int institute_id, int user_id, int language_id, int question_id)
        {
            QuestionViewModel qns = _common.GetQuestionById(institute_id, language_id, question_id);

            if (qns == null) return null;

            if (user_id > 0 && qns.author_id != user_id) return null;

            return qns;
        }

        //This endpoint allows you to associate question to subcategories
        public int AttachCategoryToQuestions(int category_id, IntegerList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<QuestionCategories> questionCategories = new List<QuestionCategories>();
                foreach (int question_id in questionIdList.IdList)
                {
                    QuestionCategories qs = _common.GetQuestionCategory(category_id, question_id);

                    if (qs != null)
                        continue;
                    else
                    {
                        questionCategories.Add(
                            new QuestionCategories()
                            {
                                QuestionId = question_id,
                                CategoryId = category_id
                            });
                    }
                    ++return_value;
                }

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

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

        public int DetachCategoryFromQuestions(int category_id, IntegerList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<QuestionCategories> questionCategories = new List<QuestionCategories>();
                foreach (int question_id in questionIdList.IdList)
                {
                    QuestionCategories qs = _common.GetQuestionCategory(category_id, question_id);
                    if (qs == null)
                        continue;
                    else
                        questionCategories.Add(qs);

                    ++return_value;
                }

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

                return_message = string.Format("{0} questions detached to the sub category.", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }
            return return_value;
        }


        public int AttachTagToQuestions(int tag_id, IntegerList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<QuestionTags> questionTags = new List<QuestionTags>();
                foreach (int question_id in questionIdList.IdList)
                {
                    QuestionTags qt = _common.GetQuestionTag(tag_id, question_id);

                    if (qt != null)
                        continue; //Its already there, so don't add this one again
                    else
                    {
                        questionTags.Add(
                            new QuestionTags()
                            {
                                QuestionId = question_id,
                                TagId = tag_id
                            });
                    }
                    ++return_value;
                }

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

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

        public int DetachTagFromQuestions(int tag_id, IntegerList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<QuestionTags> questionTags = new List<QuestionTags>();
                foreach (int question_id in questionIdList.IdList)
                {
                    QuestionTags qt = _common.GetQuestionTag(tag_id, question_id);
                    if (qt == null)
                        continue; //Its not there, so no need to delete/detach this
                    else
                        questionTags.Add(qt);

                    ++return_value;
                }

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

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


        public int PublishQuestions(int institute_id, int language_id, int user_id, int author_id, IntegerList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {

                List<Questions> questions = _context.Questions.Where(q => q.InstituteId == institute_id
                                                    && questionIdList.IdList.Contains(q.Id) 
                                                    && q.StatusCode == StatusCode.DRAFT.ToString() 
                                                    && q.IsActive == true).ToList();

                if (questions == null)
                {
                    return_message = string.Format("couldn't publish questions.", return_value);
                    return -1;
                }

                if (author_id > 0)
                {
                    List<Questions> otherQns = questions.Where(q => q.CreatedBy != author_id).ToList();
                    if (otherQns != null && otherQns.Count > 0)
                    {
                        return_message = string.Format("couldn't publish questions.", return_value);
                        return -1;
                    }
                }
                
                foreach (Questions q in questions)
                {
                    if (q == null || q.StatusCode == StatusCode.PUBLISHED.ToString())
                        continue; //Its not there, so no need to publish this
                    else
                    {
                        q.StatusCode = StatusCode.PUBLISHED.ToString();
                        q.UpdatedBy = user_id;
                        q.UpdatedOn = _common.NowIndianTime();
                        questions.Add(q);
                    }

                    ++return_value;
                }

                if (return_value > 0)
                {
                    _context.BulkUpdate(questions);
                }

                return_message = string.Format("{0} questions published successfully.", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }
            return return_value;
        }

        public int AttachBookmarkToQuestions(int user_id, BookmarkList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<BookmarkedQuestions> bookmarkedQuestions = new List<BookmarkedQuestions>();
                foreach (int question_id in questionIdList.IdList)
                {
                    BookmarkedQuestions bq = _common.GetBookmarkedQuestion(user_id, question_id);

                    if (bq != null)
                        continue; //Its already there, so don't add this one again
                    else
                    {
                        bookmarkedQuestions.Add(
                            new BookmarkedQuestions()
                            {
                                QuestionId = question_id,
                                UserId = user_id,
                                IsActive = true
                            });
                    }
                    ++return_value;
                }

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

                return_message = string.Format("the bookmark attached for {0} questions ", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }
            return return_value;
        }
        public int DetachBookmarkFromQuestions(int user_id, BookmarkList questionIdList, out string return_message)
        {
            int return_value = 0;
            try
            {
                List<BookmarkedQuestions> bookmarkedQuestions = new List<BookmarkedQuestions>();
                foreach (int question_id in questionIdList.IdList)
                {
                    BookmarkedQuestions bq = _common.GetBookmarkedQuestion(user_id, question_id);

                    if (bq == null)
                        continue; //Its not there, so no need to delete/detach this
                    else
                        bookmarkedQuestions.Add(bq);

                    ++return_value;
                }

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

                return_message = string.Format("the bookmark removed from {0} questions", return_value);
            }
            catch (Exception ex)
            {
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }
            return return_value;
        }
        #endregion

    }
}
