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


        #region Exams

        public bool CheckIfUserExist(int user_id, int institute_id)
        {
            return _common.CheckIfUserExist(institute_id, user_id);
        }


        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;
        }

        //Add new Exam
        public ExamViewModel AddNewExam(int institute_id, int language_id, int class_id, int user_id, ExamAddModel newExam, out string return_message)
        {
            return_message = string.Empty;

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

            if (cls == null) return null;

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

                //Step-2: Add Exam details
                Exams exams = new Exams
                {
                    InstituteId = institute_id,
                    ClassId = class_id,
                    ExamTypeId = newExam.examtype_id,
                    ExamStatus = StatusCode.DRAFT.ToString(),
                    LanguageId = language_id,
                    Name = newExam.name,
                    Photo = newExam.image,
                    CreatedBy = user_id,
                    UpdatedBy = user_id,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedOn = _common.NowIndianTime(),
                    IsActive = true
                };
                _context.Exams.Add(exams);
                _context.SaveChanges();
                int newExamId = exams.Id;

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

                //Step-4: Get the new Exam infomration and return as response
                ExamViewModel addedExam = _common.GetExamById(institute_id, newExamId);

                return addedExam;

            }
            catch (Exception ex)
            {
                return_message = ex.InnerException.ToString();
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        public bool isValidBatch(int institute_id, int batch_id, int user_id)
        {
            return _common.isValidBatch(institute_id, batch_id, user_id);
        }


        //Getting a specific exam
        public ExamViewModel GetExamById(int institute_id, int exam_id)
        {
            return _common.GetExamById(institute_id, exam_id);
        }

        //Getting all exams of an institute
        public List<ExamViewAllModel> GetAllExams(int institute_id, int language_id, int class_id, string sortBy, string sortOrder)
        {
            try
            {
                return _common.GetExams(institute_id, language_id, class_id, null, sortBy, sortOrder);
            }
            catch
            {
                return null;
            }
        }

        //Getting upcoming exams of an institute
        public List<ExamViewAllModel> GetUpcomingExams(int institute_id, int class_id, int user_id, string sortBy, string sortOrder)
        {
            List<Exams> exams;
            List<ExamViewAllModel> examList = new List<ExamViewAllModel>();

            exams = (from e in _context.Exams

                     where e.InstituteId == institute_id && e.ClassId == class_id && e.ExamStatus == StatusCode.PUBLISHED.ToString() &&
                                e.ExamOpenDatetime > _common.NowIndianTime() && e.IsActive == true

                     select e
                     ).ToList();

            if (exams == null || exams.Count() == 0)
                return examList;

            if (user_id > 0)
                exams = exams.Where(e => e.CreatedBy == user_id).ToList();

            if (exams == null || exams.Count() == 0)
                return examList;

            List<int> examIdList = new List<int>();
            foreach (Exams e in exams)
            {
                examIdList.Add(e.Id);
            }

            examList = _common.GetExamListByIds(institute_id, examIdList);

            //List<QuestionViewModel> questionListNew = new List<QuestionViewModel>();
            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderByDescending(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderByDescending(a => a.author_name).ToList(); break;
                    }
                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderBy(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderBy(a => a.author_name).ToList(); break;
                    }
                }
            }

            return examList;
        }

        //Getting ongoing exams of an institute
        public List<ExamViewAllModel> GetLiveExams(int institute_id, int class_id, int user_id, string sortBy, string sortOrder)
        {
            List<Exams> exams;
            List<ExamViewAllModel> examList = new List<ExamViewAllModel>();

            exams = (from e in _context.Exams

                     where e.InstituteId == institute_id && e.ClassId == class_id && e.ExamStatus == StatusCode.PUBLISHED.ToString() &&
                                e.ExamOpenDatetime < _common.NowIndianTime() && e.ExamCloseDatetime > _common.NowIndianTime() && e.IsActive == true

                     select e
                     ).ToList();

            if (exams == null || exams.Count() == 0)
                return examList;

            if (user_id > 0)
                exams = exams.Where(e => e.CreatedBy == user_id).ToList();


            List<int> examIdList = new List<int>();
            foreach (Exams e in exams)
            {
                examIdList.Add(e.Id);
            }

            examList = _common.GetExamListByIds(institute_id, examIdList);

            //List<QuestionViewModel> questionListNew = new List<QuestionViewModel>();
            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderByDescending(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderByDescending(a => a.author_name).ToList(); break;
                    }
                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderBy(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderBy(a => a.author_name).ToList(); break;
                    }
                }
            }

            return examList;
        }


        //Getting history exams of an institute
        //TODO: filter class
        public List<ExamViewAllModel> GetHistoryExams(int institute_id, int class_id, int user_id, string sortBy, string sortOrder)
        {
            List<Exams> exams;
            List<ExamViewAllModel> examList = new List<ExamViewAllModel>();

            exams = (from e in _context.Exams

                     where e.InstituteId == institute_id && e.ClassId == class_id && e.ExamStatus == StatusCode.PUBLISHED.ToString() &&
                                e.ExamCloseDatetime < _common.NowIndianTime() && e.IsActive == true

                     select e
                     ).ToList();

            if (exams == null || exams.Count() == 0)
                return examList;

            if (user_id > 0)
                exams = exams.Where(e => e.CreatedBy == user_id).ToList();


            List<int> examIdList = new List<int>();
            foreach (Exams e in exams)
            {
                examIdList.Add(e.Id);
            }

            examList = _common.GetExamListByIds(institute_id, examIdList);

            //List<QuestionViewModel> questionListNew = new List<QuestionViewModel>();
            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderByDescending(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderByDescending(a => a.author_name).ToList(); break;
                    }
                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderBy(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderBy(a => a.author_name).ToList(); break;
                    }
                }
            }

            return examList;
        }

        //Getting draft exams of an institute
        public List<ExamViewDraftModel> GetDraftExams(int institute_id, int class_id, int user_id, string sortBy, string sortOrder)
        {
            List<Exams> exams;
            List<ExamViewDraftModel> examList = new List<ExamViewDraftModel>();

            exams = (from e in _context.Exams

                     where e.InstituteId == institute_id && e.ClassId == class_id && e.ExamStatus == StatusCode.DRAFT.ToString() && e.IsActive == true

                     select e
                     ).ToList();

            if (exams == null || exams.Count() == 0)
                return examList;

            if (user_id > 0)
                exams = exams.Where(e => e.CreatedBy == user_id).ToList();


            List<int> examIdList = new List<int>();
            foreach (Exams e in exams)
            {
                examIdList.Add(e.Id);
            }

            examList = _common.GetExamDraftListByIds(institute_id, examIdList);

            //List<QuestionViewModel> questionListNew = new List<QuestionViewModel>();
            if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
            {
                if (sortOrder != null && sortOrder.Equals("D"))
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderByDescending(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderByDescending(a => a.author_name).ToList(); break;
                    }
                }
                else
                {
                    switch (sortBy.ToUpper())
                    {
                        case "ID": examList = examList.OrderBy(a => a.id).ToList(); break;
                        case "AUTHOR": examList = examList.OrderBy(a => a.author_name).ToList(); break;
                    }
                }
            }

            return examList;
        }

        public ExamViewAllModel UpdateExamOfTheInstitute(int institute_id, ExamEditModel theExam)
        {
            try
            {
                Exams exams = _context.Exams.Where(s => s.InstituteId == institute_id && s.Id == theExam.id && s.IsActive == true).FirstOrDefault();

                //if exam is in published mode then delete not possible. 
                if (exams == null || exams.ExamStatus == StatusCode.PUBLISHED.ToString())
                {
                    return null;
                }

                int count = 0;

                _context.Database.BeginTransaction();

                if (theExam.examtype_id != 0 && theExam.examtype_id != exams.ExamTypeId) { exams.ExamTypeId = theExam.examtype_id; count++; }
                if (theExam.name != null && theExam.name != exams.Name) { exams.Name = theExam.name; count++; }

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

                _context.Exams.Update(exams);
                _context.SaveChanges();
                _context.Database.CommitTransaction();
                return _common.GetExamBasicById(institute_id, exams.Id);
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        public ExamSectionViewModel UpdateExamSectionOfTheInstitute(ExamSectionEditModel theExamSection)
        {
            try
            {
                ExamSections examsections = _context.ExamSections.
                                                Where(s => s.Id == theExamSection.id).
                                                Where(s => s.IsActive == true).FirstOrDefault();

                if (examsections == null) { return null; }
                Exams exams = _context.Exams.Where(e => e.Id == examsections.ExamId).FirstOrDefault();

                //if exam is in published mode then edit not possible. 
                if (exams == null || exams.ExamStatus == StatusCode.PUBLISHED.ToString())
                {
                    return null;
                }

                int count = 0;

                _context.Database.BeginTransaction();

                if (theExamSection.author_id != 0 && theExamSection.author_id != examsections.UserId) { examsections.UserId = theExamSection.author_id; count++; }
                if (theExamSection.subject_id != 0 && theExamSection.subject_id != examsections.SubjectId) { examsections.SubjectId = theExamSection.subject_id; count++; }
                if (theExamSection.isActive != examsections.IsActive) { examsections.IsActive = theExamSection.isActive; count++; }

                _context.ExamSections.Update(examsections);
                _context.SaveChanges();
                _context.Database.CommitTransaction();
                return _common.GetExamSectionById(examsections.Id);
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        //Getting a specific exam
        public ExamSectionViewModel GetExamSectionById(int exam_section_id)
        {
            return _common.GetExamSectionById(exam_section_id);
        }

        public IntegerSectionList ReorderExamSectionOfTheExam(int institute_id, int user_id, int exam_id, ExamSectionsList examSectionList)
        {
            IntegerSectionList sectionAdded = new IntegerSectionList();
            sectionAdded.idList = new List<int>();

            Exams exams = _context.Exams.Where(e => e.InstituteId == institute_id && e.Id == exam_id && e.IsActive == true
                            && e.ExamStatus == StatusCode.DRAFT.ToString()).FirstOrDefault();

            //if exam is in published mode then edit not possible. 
            if (exams == null)
            {
                return null;
            }

            try
            {
                List<ExamSections> examsections = _context.ExamSections.
                                                    Where(s => s.ExamId == exam_id).
                                                    Where(s => s.IsActive == true).ToList();

                List<int> sectionIdList = new List<int>();

                for (int i = 0; i < examsections.Count; i++)
                {
                    sectionIdList.Add(examsections[i].Id);
                }

                _context.Database.BeginTransaction();


                Dictionary<int, ExamSections> d = new Dictionary<int, ExamSections>();
                for(int i = 0; i < examsections.Count; i++)
                {
                    d.Add(examsections[i].Id, examsections[i]);
                }

                for (int i = 0; i < examSectionList.idList.Count; i++)
                {
                    if(d.ContainsKey(examSectionList.idList[i]))
                    {
                        ExamSections es = d[examSectionList.idList[i]];
                        es.SubjectSequence = (short)(i + 1);
                        es.UserId = user_id;
                        _context.ExamSections.Update(es);
                        _context.SaveChanges();
                    }
                    else
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }
                }

                _context.Database.CommitTransaction();
                sectionAdded.idList = (from s in _context.ExamSections
                                       where s.ExamId == exam_id && s.IsActive == true
                                       select s.Id).ToList();

                return sectionAdded;
            }
            catch (Exception e)
            {
                string str = e.Message.ToString();
                _context.Database.RollbackTransaction();
                return null;
            }
        }


        /*
                public ExamSectionViewModel ReorderQuestionsOfTheExamSection(int institute_id, int exam_section_id, QuestionsList questionList)
                {
                    //Check the exam status is not published or its not started

                    try
                    {
                        List<ExamQuestionsMarkWeight> questions = _context.ExamQuestionsMarkWeight.
                                                                    Where(s => s.ExamSectionId == exam_section_id).
                                                                    Where(s => s.IsActive == true).ToList();

                        List<int> questionIdList = new List<int>();

                        for (int i = 0; i < questions.Count; i++)
                        {
                            questionIdList.Add(questions[i].QuestionId);
                        }

                        //Check if the list of section sent in body list param contains all sections
                        List<int> distinct = questionIdList.Except(questionList.idList).ToList();
                        if (distinct.Count == 0)
                            distinct = questionList.idList.Except(questionIdList).ToList();

                        if (distinct.Count != 0)
                        {
                            return null;
                        }


                        _context.Database.BeginTransaction();

                        for (int i = 0; i < questions.Count; i++)
                        {
                            short newSeq = (short)(questionList.idList.IndexOf(questions[i].QuestionId) + 1);
                            if (questions[i].QuestionSequence != newSeq)
                            {
                                questions[i].QuestionSequence = newSeq;
                                _context.ExamQuestionsMarkWeight.Update(questions[i]);
                                _context.SaveChanges();
                            }
                        }

                        _context.Database.CommitTransaction();
                        return _common.GetExamSectionById(exam_section_id);
                    }
                    catch
                    {
                        _context.Database.RollbackTransaction();
                        return null;
                    }
                }
        */

        public List<SectionQuestionDetails> GetQuestionsOfTheSection(int institute_id, int user_id, int exam_section_id, string sortBy, string sortOrder)
        {

            List<SectionQuestionDetails> lqvam = new List<SectionQuestionDetails>();

            try
            {
                ExamSections es = _context.ExamSections.Where(s => s.Id == exam_section_id && s.IsActive == true).FirstOrDefault();
                Exams ex = null;
                if (es != null)
                {
                     ex = _context.Exams.Where(e => e.Id == es.ExamId && e.InstituteId == institute_id && e.IsActive == true).FirstOrDefault();
                }

                if(ex == null)
                {
                    return lqvam;
                }

                List<ExamQuestionsMarkWeight> questions = _context.ExamQuestionsMarkWeight.
                                                            Where(s => s.ExamSectionId == exam_section_id).
                                                            Where(s => s.IsActive == true).ToList();

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

                List<int> questionIdList = new List<int>();

                //questionIdList.Add(questions[i].QuestionId);
                lqvam = (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 idList.Contains(q.Id)
                                       && q.InstituteId == institute_id
                                       && ql.LanguageId == ex.LanguageId && ql.IsActive == true
                                       && qt.IsActive == true


                            select new SectionQuestionDetails
                            {
                                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,
                                correct_mark = d[q.Id].MarkForCorrectAnswer,
                                incorrect_mark = d[q.Id].MarkForWrongAnswer,
                                sequence = d[q.Id].QuestionSequence,
                                isBookmarked =
                                         _context.BookmarkedQuestions.
                                         Where(b => b.UserId == user_id).
                                         Where(b => b.QuestionId == q.Id).FirstOrDefault().IsActive
                            }
                            ).ToList();

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

        //exam section & question from user's intitute, questlist has all questions attached to this exam section
        public ExamSectionViewModel AssignMarksToExamSection(int institute_id, int exam_section_id, QuestionMarksList qList)
        {
            //Check the exam status is not published or its not started
            int return_value = 0;
            try
            {
                ExamSections examSection = (from s in _context.ExamSections
                                            join e in _context.Exams on s.ExamId equals e.Id

                                            where s.Id == exam_section_id && s.IsActive == true
                                            && e.InstituteId == institute_id && e.ExamStatus == StatusCode.DRAFT.ToString() && e.IsActive == true select s).FirstOrDefault();

                                            

                if (examSection == null)
                {
                    return null;
                }

                _context.Database.BeginTransaction();

                short nSeq = 0;
                List<ExamQuestionsMarkWeight> examSectionQuestions = new List<ExamQuestionsMarkWeight>();
                foreach (QuestionMarks newQuestionMark in qList.qnsMarkList)
                {
                    ExamQuestionsMarkWeight eqmw = _common.GetExamSectionQuestion(institute_id, exam_section_id, newQuestionMark.id);

                    nSeq++;

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

                    else
                    {
                        eqmw.MarkForCorrectAnswer = newQuestionMark.correct_mark;
                        eqmw.MarkForWrongAnswer = newQuestionMark.negative_mark;
                        eqmw.QuestionSequence = nSeq;
                        examSectionQuestions.Add(eqmw);
                    }

                    ++return_value;
                }


                if(return_value > 0)
                {
                    _context.BulkUpdate(examSectionQuestions);
                    examSection.Status = StatusCode.PUBLISHED.ToString();
                    examSection.UpdatedOn = _common.NowIndianTime();
                    _context.ExamSections.Update(examSection);
                    _context.SaveChanges();
                }

                _context.Database.CommitTransaction();

                return _common.GetExamSectionById(exam_section_id);
            }
            catch (Exception ex)
            {
                string return_message = ex.InnerException.ToString();
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        /*
        public int SubscriptionType(int institute_id, int exam_id, short type)
        {
            int return_value = -1;
            try
            {                
                Exams exams = _context.Exams.Where(s => s.InstituteId == institute_id && s.Id == exam_id && s.IsActive == true).FirstOrDefault();
                if (exams == null)
                    return (int)Message.NotAllowedToResource;

                if (exams.SubscriptionType == type)
                    return type;
                
                exams.SubscriptionType = type;
                exams.UpdatedOn = _common.NowIndianTime();

                _context.Database.BeginTransaction();
                _context.Exams.Update(exams);
                _context.SaveChanges();
                _context.Database.CommitTransaction();
                return_value = type;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return (int)Message.ObjectNotUpdated;
            }

            return return_value;
        }
        */

        //(exam state == draft, section >= 1, all section == submited, start datetime & end datetime gt now, section duration lt totaltime || totaltime == -1, count of batch gt 1)
        public ExamViewAllModel PublishExam(int institute_id, int user_id, int exam_id, ExamPublishModel scheduleExam)
        {
            try
            {
                _context.Database.BeginTransaction();

                //Valid Start & end date
                if (DateTime.Compare(scheduleExam.start_date, scheduleExam.end_date) > 0 ||
                        DateTime.Compare(_common.NowIndianTime(), (DateTime)scheduleExam.end_date) > 0 ||
                           DateTime.Compare((DateTime)scheduleExam.start_date, (DateTime)scheduleExam.end_date) > 0)
                {
                    return null;
                }

                if(DateTime.Compare(_common.NowIndianTime(), scheduleExam.start_date) > 0)
                {
                    scheduleExam.start_date = _common.NowIndianTime();
                }

                if (scheduleExam.attempts_allowed < 1)
                {
                    return null;
                }

                /*
                //valid ugergroups in the list
                if(scheduleExam.batch_list == null || scheduleExam.batch_list.idList.Count < 1)
                {
                    return null;
                }
                

                foreach(int batchId in scheduleExam.batch_list.idList)
                {
                    UserGroups ug = _context.UserGroups.Where(u => u.Id == batchId && u.IsActive == true).FirstOrDefault();
                    if(ug == null)
                    {
                        return null;
                    }
                }
                */

                Exams exams = _context.Exams.Where(s => s.Id == exam_id && s.IsActive == true).FirstOrDefault();
                ExamViewModel exam = _common.GetExamById(institute_id, exam_id);
                short total_duration = 0;

                //State shouldbe draft, atleast one section
                if (exam == null || exam.exam_status == StatusCode.PUBLISHED.ToString() || 
                    exam.sections.Count < 1)
                {
                    return null;
                }

                int flag_section_state = 1;
                //count total duration of all sections
                for (int i = 0; i < exam.sections.Count; i++)
                {
                    //TODO: Need to enable when you add state of section 
                    /*
                    if(exam.sections[i].section_state != StatusCode.PUBLISHED.ToString())
                    {
                        flag_section_state = 0;
                    }
                    */
                    //total_duration += (short)exam.sections[i].section_duration;
                    //TBD: Exam section status submitted: true/false
                }

                if(flag_section_state == 0)
                {
                    //TODO: section state field to be added in db
                    return null;
                }

                if (scheduleExam.exam_duration != -1 && total_duration > scheduleExam.exam_duration)
                {
                    return null;
                }

                if (scheduleExam.exam_duration == -1)
                {
                    scheduleExam.exam_duration = total_duration;
                }

                //TBD: Check the examsection status is submitted\
                exams.ExamOpenDatetime = scheduleExam.start_date;
                exams.ExamCloseDatetime = scheduleExam.end_date;
                exams.AttemptsAllowed = scheduleExam.attempts_allowed;
                exams.ExamDurationInSeconds = scheduleExam.exam_duration;
                exams.UpdatedOn = _common.NowIndianTime();
                exams.UpdatedBy = user_id;
                exams.ExamStatus = StatusCode.PUBLISHED.ToString();

                if(scheduleExam.instruction != null && scheduleExam.instruction.Length > 0)
                {
                    exams.Instruction = scheduleExam.instruction;
                }

                _context.Exams.Update(exams);
                _context.SaveChanges();

                _context.Database.CommitTransaction();

                //AttachUserGroups(user_id, exam.id, scheduleExam.batch_list);
                
                return _common.GetExamBasicById(institute_id, exams.Id);
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        public int StopExam(int exam_id)
        {
            int return_value = -1;
            try
            {
                _context.Database.BeginTransaction();

                Exams exams = _context.Exams.Where(s => s.Id == exam_id).Where(s => s.IsActive == true).FirstOrDefault();

                int count = 0;
                if (exams.ExamStatus != null && exams.ExamStatus != StatusCode.DRAFT.ToString()) { exams.ExamStatus = StatusCode.DRAFT.ToString(); count++; }

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

                _context.Exams.Update(exams);
                _context.SaveChanges();
                _context.Database.CommitTransaction();
                return_value = exam_id;
            }
            catch
            {
                _context.Database.RollbackTransaction();
                return -1;
            }

            return return_value;
        }

        public int DeleteExam(int institute_id, int user_id, int exam_id)
        {
            int return_value = -1;
            try
            {
                Exams exams = _context.Exams.Where(e => e.InstituteId == institute_id && e.Id == exam_id && e.CreatedBy == user_id && e.IsActive == true).FirstOrDefault();

                //if exam is in published mode then delete not possible. 
                if (exams == null || exams.ExamStatus == StatusCode.PUBLISHED.ToString())
                {
                    return -1;
                }

                exams.IsActive = false;
                exams.UpdatedBy = user_id;
                exams.UpdatedOn = _common.NowIndianTime();
                
                _context.Exams.Update(exams);
                _context.SaveChanges();

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

        //Getting all exams of an user
        public List<ExamViewAllModel> GetAllExams(int institute_id, int language_id, int class_id, int user_id, string sortBy, string sortOrder)
        {
            try
            {
                return _common.GetExams(institute_id, language_id, class_id, user_id, sortBy, sortOrder);
            }
            catch
            {
                return null;
            }
        }

        //Add new Exam Section
        public ExamSectionViewModel AddNewExamSection(int exam_id, ExamSectionAddModel newExamSection, out string return_message)
        {
            return_message = string.Empty;
            try
            {
                Exams exams = _context.Exams.Where(e => e.Id == exam_id).Where(e => e.IsActive == true).FirstOrDefault();

                //if exam is in published mode then edit not possible. 
                if (exams == null || exams.ExamStatus == "PUB")
                {
                    return null;
                }

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

                //Step-2: Add Exam Section details
                ExamSections examSections = new ExamSections
                {
                    ExamId = exam_id,
                    SubjectId = newExamSection.subject_id,
                    UserId = newExamSection.author_id,
                    SubjectDuration = newExamSection.section_duration,
                    CreatedOn = _common.NowIndianTime(),
                    UpdatedOn = _common.NowIndianTime(),
                    IsActive = true

                };
                _context.ExamSections.Add(examSections);
                _context.SaveChanges();
                int newExamSectionId = examSections.Id;


                //Step-3: Get the new Exam infomration and return as response
                ExamSectionViewModel addedExamSection = _common.GetExamSectionById(newExamSectionId);

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

                if (addedExamSection != null)
                    return_message = string.Format("{0} - Exam Section added", addedExamSection.subject_name);

                return addedExamSection;

            }
            catch (Exception ex)
            {
                return_message = ex.InnerException.ToString();
                _context.Database.RollbackTransaction();
                return null;
            }
        }

        //Attach Exam Sections
        public IntegerSectionList AddNewExamSections(int institute_id, int exam_id, int user_id, IntegerSectionList sectionIdList, out string return_message)
        {
            IntegerSectionList sectionAdded = new IntegerSectionList();
            sectionAdded.idList = new List<int>();

            return_message = string.Empty;
            int return_value = 0;
            try
            {
                Exams exams = _context.Exams.Where(e => e.InstituteId == institute_id && e.Id == exam_id && e.IsActive == true).FirstOrDefault();

                //if exam is in published mode then edit not possible. 
                if (exams == null || exams.ExamStatus == StatusCode.PUBLISHED.ToString())
                {
                    return null;
                }

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

                List<ExamSections> presentSections = _context.ExamSections.Where(s => s.ExamId == exam_id && s.IsActive == true).ToList(); 
                List<ExamSections> examSectionsList = new List<ExamSections>();
                int nSeq = 0;

                if(presentSections != null)
                {
                    nSeq = presentSections.Count + 1;
                }

                foreach (int section_id in sectionIdList.idList)
                {
                    Subjects sub = _context.Subjects.Where(s => s.Id == section_id && s.IsActive == true).FirstOrDefault();
                    if (sub == null) return null;

                    //ExamSections es = _common.GetExamSection(exam_id, section_id);
                    //bool l = presentSections.Select(x => x.Id).Contains(section_id);
                    //Check if the section is already added
                    if (presentSections.Select(x => x.Id).Contains(section_id))
                        continue;
                    else
                    {
                        examSectionsList.Add(
                            new ExamSections()
                            {
                                ExamId = exam_id,
                                SubjectId = section_id,
                                UserId = user_id,
                                CreatedBy = user_id,
                                UpdatedBy = user_id,
                                CreatedOn = _common.NowIndianTime(),
                                UpdatedOn = _common.NowIndianTime(),
                                Status = StatusCode.DRAFT.ToString(),
                                SubjectSequence = (short)nSeq,
                                IsActive = true
                            }
                         );
                        nSeq++;
                    }
                    ++return_value;
                }

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

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

                sectionAdded.idList = (from s in _context.ExamSections
                                       where s.ExamId == exam_id && s.IsActive == true
                                       select s.Id).ToList();

                return_message = string.Format("{0} sections attached to the Exam", return_value);
            }
            catch (Exception ex)
            {
                return_message = ex.InnerException.ToString();
                _context.Database.RollbackTransaction();
                return null;
            }

            return sectionAdded;
        }


        public int DeleteExamSection(int exam_section_id)
        {
            int return_value;
            try
            {
                ExamSections examsection = _context.ExamSections.
                                        Where(e => e.Id == exam_section_id).
                                        Where(e => e.IsActive == true).FirstOrDefault();

                if (examsection == null) { return -1; }
                
                Exams exams = _context.Exams.
                    Where(e => e.Id == examsection.ExamId).
                    Where(e => e.IsActive == true).FirstOrDefault();

                //if exam is in published mode then delete not possible. 
                if (exams == null || exams.ExamStatus == "PUB")
                {
                    return -1;
                }

                examsection.IsActive = false;
                examsection.UpdatedOn = _common.NowIndianTime();
                exams.UpdatedOn = _common.NowIndianTime();
                
                _context.ExamSections.Update(examsection);
                _context.Exams.Update(exams);
                _context.SaveChanges();

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

        //This endpoint allows you to associate question to subcategories
        public int AttachQuestionsToExamSections(int institute_id, int user_id, int exam_section_id, QuestionsList questionIdList, out string return_message)
        {
            int return_value = 0;

            ExamSections examSection = (from s in _context.ExamSections
                                        join e in _context.Exams on s.ExamId equals e.Id

                                        where s.Id == exam_section_id && s.IsActive == true
                                        && e.InstituteId == institute_id && e.ExamStatus != StatusCode.PUBLISHED.ToString() && e.IsActive == true

                                        select new ExamSections()).FirstOrDefault();

            if (examSection == null)
            {
                return_message = string.Format("{0} questions attached the Exam Section", return_value);
                return (int)Message.NotAllowedToResource;
            }

            List<Questions> qns = (from q in _context.Questions
                                        
                                        where questionIdList.idList.Contains(q.Id)

                                        select q).ToList();


            if (qns == null)
            {
                return_message = string.Format("{0} questions attached the Exam Section", return_value);
                return (int)Message.NotAllowedToResource;
            }

            qns = qns.Where(q => q.InstituteId == institute_id && q.IsActive == true).ToList();
            if(qns == null || qns.Count != questionIdList.idList.Count)
            {
                return_message = string.Format("{0} questions attached the Exam Section", return_value);
                return (int)Message.NotAllowedToResource;
            }

            if(user_id > 0)
            {
                qns = qns.Where(q => q.CreatedBy == user_id).ToList();
                if (qns == null || qns.Count != questionIdList.idList.Count)
                {
                    return_message = string.Format("{0} questions attached the Exam Section", return_value);
                    return (int)Message.NotAllowedToResource;
                }
            }
              
            try
            {
                List<ExamQuestionsMarkWeight> examSectionQuestions = new List<ExamQuestionsMarkWeight>();
                foreach (int question_id in questionIdList.idList)
                {
                    //TBD:Hardcoded the return value to null
                    ExamQuestionsMarkWeight es = _common.GetExamSectionQuestion(institute_id, exam_section_id, question_id);

                    if (es != null)
                        continue;
                    else
                    {
                        examSectionQuestions.Add(
                            new ExamQuestionsMarkWeight()
                            {
                                QuestionId = question_id,
                                ExamSectionId = exam_section_id
                            });
                    }
                    ++return_value;
                }

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

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

        // Attach & detach only possible in draft state, if submitted state then it will convert to draft again. if published then it cant 
        public int DetachExamSectionFromQuestions(int institute_id, int exam_section_id, QuestionsList questionIdList, out string return_message)
        {
            int return_value = 0;
            ExamSections examSection = (from s in _context.ExamSections
                                        join e in _context.Exams on s.ExamId equals e.Id

                                        where s.Id == exam_section_id && s.IsActive == true
                                        && e.InstituteId == institute_id && e.ExamStatus != StatusCode.PUBLISHED.ToString() && e.IsActive == true

                                        select s).FirstOrDefault();

            if (examSection == null)
            {
                return_message = string.Format("{0} questions detached the Exam Section", return_value);
                return (int)Message.NotAllowedToResource;
            }
            
            try
            {
                List<ExamQuestionsMarkWeight> examSectionQuestions = new List<ExamQuestionsMarkWeight>();
                foreach (int question_id in questionIdList.idList)
                {
                    ExamQuestionsMarkWeight es = _common.GetExamSectionQuestion(institute_id, exam_section_id, question_id);

                    if (es == null)
                        continue;
                    else
                    {
                        examSectionQuestions.Add(es);
                        ++return_value;
                    }
                       
                }

                if (return_value > 0)
                {
                    

                    _context.BulkDelete(examSectionQuestions);

                    int nQns = _context.ExamQuestionsMarkWeight.Where(q => q.ExamSectionId == exam_section_id && q.IsActive == true && q.MarkForCorrectAnswer != null && q.MarkForWrongAnswer != null && q.QuestionSequence != null).Count();
                    if(nQns == 0 && examSection.Status != StatusCode.DRAFT.ToString())
                    {
                        _context.Database.BeginTransaction();
                        examSection.Status = StatusCode.DRAFT.ToString();
                        examSection.UpdatedOn = _common.NowIndianTime();
                        _context.ExamSections.Update(examSection);
                        _context.SaveChanges();
                        _context.Database.CommitTransaction();
                    }                    
                }

                return_message = string.Format("{0} questions detached to the exam section.", return_value);
            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return_value = -1;
                return_message = ex.InnerException.ToString();
            }

            return return_value;
        }

        //This endpoint allows you to attach usergroups to a exam
        public int AttachUserGroups(int institute_id, int user_id, int exam_id, UserGroupsList userGroupsList)
        {
            int return_value = 0;
            Exams exams = _context.Exams.Where(e => e.Id == exam_id && e.InstituteId == institute_id && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.IsActive == true).FirstOrDefault();
            if(exams == null)
            {
                return -1;
            }

            try
            {
                List<UserGroupExams> userGroupExams = new List<UserGroupExams>();
                foreach (int userGroup_id in userGroupsList.idList)
                {

                    //TBD:Hardcoded the return value to null

                    UserGroupExams uge = _common.GetUserGroupExams(institute_id, exam_id, userGroup_id);

                    if (uge != null)
                        continue;

                    else
                    {
                        userGroupExams.Add(
                            new UserGroupExams()
                            {
                                UserGroupId = userGroup_id,
                                ExamId = exam_id,
                                CreatedOn = _common.NowIndianTime(),
                                CreatedBy = user_id,
                                UpdatedOn = _common.NowIndianTime(),
                                UpdatedBy = user_id,
                                IsActive = true                                
                            });
                    }
                    ++return_value;
                }

                if (return_value > 0)
                {
                    _context.BulkInsert(userGroupExams);
                }
            }
            catch (Exception ex)
            {
                return_value = -1;
            }
            
            return return_value;
        }

        //This endpoint allows you to detach usergroups to a exam
        public int DetachUserGroups(int institute_id, int user_id, int exam_id, UserGroupsList userGroupsList)
        {
            int return_value = 0;
            Exams exams = _context.Exams.Where(e => e.Id == exam_id && e.InstituteId == institute_id && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.IsActive == true).FirstOrDefault();
            if (exams == null)
            {
                return -1;
            }


            //Check the state. if published send error code. else convert to DFT
            try
            {
                List<UserGroupExams> userGroupExams = new List<UserGroupExams>();
                foreach (int userGroup_id in userGroupsList.idList)
                {
                    //TBD:Hardcoded the return value to null
                    UserGroupExams uge = _common.GetUserGroupExams(institute_id, exam_id, userGroup_id);

                    if (uge == null || uge.IsActive == false)
                        continue;
                    else
                    {
                        userGroupExams.Add(uge);
                        ++return_value;
                    }
                }

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

            }
            catch (Exception ex)
            {
                return_value = -1;
            }

            return return_value;
        }

        //This endpoint returns list of usergroups to a exam
        public UserGroupsList GetBatchListsOfTheExam(int institute_id, int user_id, int exam_id)
        {
            Exams exams = _context.Exams.Where(e => e.Id == exam_id && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.IsActive == true).FirstOrDefault();
            if (exams == null)
            {
                return null;
            }

            try
            {
                UserGroupsList ugl = new UserGroupsList();

                ugl.idList = (from u in _context.UserGroupExams
                                      where u.ExamId == exam_id && u.IsActive == true
                                      select u.UserGroupId).ToList();

                return ugl;

            }
            catch (Exception ex)
            {
                return null;
            }

            return null;
        }

        #endregion

        #region ExamAttempts
        /*

                        public DurationView HeartBeat(int attempt_id, int user_id)
                {
                    DurationView time = new DurationView();
                    time.time_left = -1;

                    ExamAttempts attempts = _context.ExamAttempts.Where(a => a.Id == attempt_id && a.Status != State.COMPLETED &&
                                                a.CreatedBy == user_id && a.IsActive == true).FirstOrDefault();
                    if (attempts == null)
                    {
                        return null;
                    }

                    if (attempts.Status == State.PAUSE)
                    {
                        time.time_left = attempts.RemainingTimeSeconds;
                        return time;
                    }

                    Exams exams = _context.Exams.Where(e => e.Id == attempts.ExamId).FirstOrDefault();

                    //Check if user still has time to update the answers
                    TimeSpan pausedtime = TimeSpan.Parse(attempts.PuasedPeriod);
                    TimeSpan time_diff = (TimeSpan)(_common.NowIndianTime() - attempts.CreatedOn);
                    time_diff -= pausedtime;
                    int time_diff_seconds = (int)time_diff.TotalSeconds;

                    attempts.RemainingTimeSeconds = (int)exams.ExamDurationInSeconds - time_diff_seconds;

                    if(attempts.RemainingTimeSeconds <= 0 || exams.ExamCloseDatetime < _common.NowIndianTime())
                    {
                        EndExamAttempt(user_id, attempts.Id);

                        time.time_left = 0;
                        return time;
                    }

                    time.time_left = attempts.RemainingTimeSeconds;

                    return time;
                }

                public DurationView UpdateAnswer(int attempt_id, int user_id, QuestionAnswerViewModel responses)
                {
                    DurationView time = HeartBeat(attempt_id, user_id);

                    if (time == null || time.time_left <= 0) return time;

                    ExamAttempts attempts = _context.ExamAttempts.Where(a => a.Id == attempt_id).FirstOrDefault();

                    if (responses == null )
                    {
                        return time;
                    }

                    ExamAttemptsAnswer aaa = (from aa in _context.ExamAttemptsAnswer

                                                    where aa.ExamAttemptId == attempt_id && aa.QuestionId == responses.question_id
                                                    select aa).ToList().FirstOrDefault();

                    try
                    {
                        _context.Database.BeginTransaction();
                        if (aaa == null)
                        {
                                //create
                                string jsonAnswer = null;
                                string strAnsComma = null;
                                if (responses.answers != null)
                                {
                                    jsonAnswer = JsonSerializer.Serialize(responses.answers);
                                    List<string> strAns = new List<string>();
                                    foreach (OptionsSelectedViewModel osvm in responses.answers)
                                    {
                                        strAns.Add(osvm.id.ToString());
                                    }
                                    strAnsComma = String.Join(",", strAns);
                                }

                                ExamAttemptsAnswer newAnswer = new ExamAttemptsAnswer()
                                {
                                            QuestionId = responses.question_id,
                                            ExamAttemptId = attempt_id,
                                            DateOfAnswer = _common.NowIndianTime(),
                                            AnswerDurationSeconds = responses.answer_duration,
                                            StudentAnswer = strAnsComma,
                                            IsReviewed = responses.is_reviewed,
                                            IsVisited = true
                                };
                                _context.ExamAttemptsAnswer.Add(newAnswer);
                                _context.SaveChanges();
                        }
                        else
                        {
                            //update
                            List<string> strAns = new List<string>();
                            foreach (OptionsSelectedViewModel osvm in responses.answers)
                            {
                                strAns.Add(osvm.id.ToString());
                            }
                            string strAnsComma = String.Join(",", strAns);
                            aaa.IsReviewed = responses.is_reviewed;
                            aaa.IsVisited = true;
                            aaa.StudentAnswer = strAnsComma; //convert to json and adda
                            aaa.AnswerDurationSeconds = responses.answer_duration;
                            aaa.DateOfAnswer = _common.NowIndianTime();
                            aaa.IsActive = true;

                            _context.ExamAttemptsAnswer.Update(aaa);
                            _context.SaveChanges();

                        }

                        _context.ExamAttempts.Update(attempts);
                        _context.SaveChanges();

                        _context.Database.CommitTransaction();
                    }
                    catch (Exception e)
                    {
                        string str = e.Message.ToString();
                        _context.Database.RollbackTransaction();
                        time.time_left = -1;
                        return time;
                    }

                    return time;
                }


                public ExamDetailViewModel GetExamDetails(int institute_id, int user_id, int exam_id)
                {
                    ExamDetailViewModel details = new ExamDetailViewModel();

                    //Check exam validity            
                    Exams exam = _context.Exams.Where(e => e.Id == exam_id && e.InstituteId == institute_id
                                && e.IsActive == true && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.ExamCloseDatetime > _common.NowIndianTime()).FirstOrDefault();

                    if (exam == null) return null;

                    details.exam_id = exam.Id;
                    details.exam_name = exam.Name;
                    details.exam_instruction = exam.Instruction;
                    details.total_time = (int)exam.ExamDurationInSeconds;
                    details.total_plays = _context.ExamAttempts.Where(a => a.ExamId == exam_id && a.IsActive == true).Select(l => l.CreatedBy).Distinct().Count();
                    details.total_likes = 0;
                    details.author_id = exam.CreatedBy;

                    bool isBookmarked = false;
                    BookmarkedExams be = _context.BookmarkedExams.Where(b => b.ExamId == exam_id && b.UserId == user_id && b.IsActive == true).FirstOrDefault();
                    if (be == null) 
                    { 
                        isBookmarked = false; 
                    } else
                    {
                        isBookmarked = (bool)be.IsActive;
                    }
                    details.isLiked = isBookmarked;

                    Users author = _context.Users.Where(u => u.Id == exam.CreatedBy && u.IsActive == true).FirstOrDefault();
                    if(author != null)
                    {
                        details.author_name = author.FirstName;
                        details.author_image = author.Photo;
                    }

                    //total attempts taken
                    int attemptsTaken = 0;
                    List<ExamAttempts> allLastAttempts = _context.ExamAttempts.Where(a => a.ExamId == exam_id && a.CreatedBy == user_id).ToList();

                    //1st attempt
                    if (allLastAttempts == null || allLastAttempts.Count == 0)
                    {
                        details.attempt_id = -1;
                        details.attempt_status = null;
                        details.time_left = (int)exam.ExamDurationInSeconds;

                        return details;
                    }

                    ExamAttempts lastAttempt = allLastAttempts.OrderByDescending(l => l.Id).FirstOrDefault();
                    attemptsTaken = allLastAttempts.Count;
                    if (attemptsTaken < exam.AttemptsAllowed)
                    {
                        DurationView time = HeartBeat(lastAttempt.Id, user_id);
                        lastAttempt = _context.ExamAttempts.Where(a => a.Id == lastAttempt.Id).FirstOrDefault();

                        if(lastAttempt.Status == State.COMPLETED)
                        {
                            details.attempt_id = lastAttempt.Id;
                            details.attempt_status = lastAttempt.Status;
                            details.time_left = (int)exam.ExamDurationInSeconds;

                            return details;
                        }
                        else
                        {
                            details.attempt_id = lastAttempt.Id;
                            details.attempt_status = lastAttempt.Status;
                            details.time_left = time.time_left;

                            return details;
                        }

                    }
                    return details;
                }

                //Returns a new attempt id if its first attempt or the last attempt is in completed state
                //if Pause then it resumes and send the id
                //if start state then it checks the time left and returns the id
                public int AddNewAttemptOfTheExam(int institute_id, int user_id, int exam_id)
                {
                    int newAttemptId = 0;
                    ExamAttempts lastAttempt = null;
                    //Check exam validity            
                    Exams exam = _context.Exams.Where(e => e.Id == exam_id && e.InstituteId == institute_id
                                && e.IsActive == true && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.ExamCloseDatetime > _common.NowIndianTime()).FirstOrDefault();

                    if (exam == null) return (int)Message.InvalidInput;

                    //total attempts taken and is more allowed?
                    int attemptsTaken = 0;
                    List<ExamAttempts> allLastAttempts = _context.ExamAttempts.Where(a => a.ExamId == exam_id && a.CreatedBy == user_id).ToList();
                    if (allLastAttempts != null) attemptsTaken = allLastAttempts.Count;
                    if (attemptsTaken >= exam.AttemptsAllowed)
                    {
                        return (int)Message.InvalidOperation;
                    }

                    //get last attempt and its state
                    if (allLastAttempts != null || allLastAttempts.Count > 0)
                    {
                        lastAttempt = allLastAttempts.OrderByDescending(l => l.Id).FirstOrDefault();
                    }

                    //1st attempt
                    if (lastAttempt == null || lastAttempt.Status == State.COMPLETED)
                    {
                        newAttemptId = _common._ea_createNewAttempt(user_id, exam_id, (int)exam.ExamDurationInSeconds);
                        if (newAttemptId <= 0) return -1;
                        return newAttemptId;//_common.GetExamAttemptById(newAttemptId);
                    }

                    //last attempt is still not completed 
                    if (lastAttempt.Status == State.PAUSE)
                    {
                        lastAttempt.Status = State.RESUME;
                        lastAttempt.UpdatedOn = _common.NowIndianTime();
                        lastAttempt.PuasedPeriod = (_common.NowIndianTime() - lastAttempt.LastPausedAt).ToString();
                        _context.ExamAttempts.Update(lastAttempt);
                        _context.SaveChanges();

                        return lastAttempt.Id;//_common.GetExamAttemptById(lastAttempt.Id);
                    }

                    if (lastAttempt.Status == State.START || lastAttempt.Status == State.RESUME) //check if time left, if so resume and start else complete it and start a new one
                    {
                        DurationView time = HeartBeat(lastAttempt.Id, user_id);
                        if (time == null || time.time_left <= 0) return -1;

                        lastAttempt = _context.ExamAttempts.Where(a => a.Id == lastAttempt.Id).FirstOrDefault();
                        lastAttempt.Status = State.RESUME;
                        lastAttempt.UpdatedOn = _common.NowIndianTime();
                        lastAttempt.UpdatedBy = user_id;
                        _context.ExamAttempts.Update(lastAttempt);
                        _context.SaveChanges();

                        return lastAttempt.Id;//_common.GetExamAttemptById(lastAttempt.Id); 
                    }

                    //if no more attempts allowed            
                    return (int)Message.InvalidOperation;
                }

                public int AttachBookmarkToExams(int institute_id, int batch_id, int user_id, int exam_id, out string return_message)
                {
                    int return_value = 0;
                    try
                    {

                        int id = (from uge in _context.UserGroupExams
                                  join e in _context.Exams on uge.ExamId equals e.Id
                                  join ug in _context.UserGroups on uge.UserGroupId equals ug.Id
                                  join ugm in _context.UserGroupMembers on ug.Id equals ugm.UserGroupId

                                  where uge.UserGroupId == batch_id && uge.ExamId == exam_id && uge.IsActive == true
                                  && e.InstituteId == institute_id && e.Id == exam_id && e.IsActive == true
                                  && ug.Id == batch_id && ug.IsActive == true
                                  && ugm.UserId == user_id && ugm.UserGroupId == batch_id && ugm.IsActive == true
                                  select uge).FirstOrDefault().ExamId;

                        if (id != exam_id)
                        {
                            return_message = string.Format("Invalid details ");
                            return -1;
                        }

                        List<BookmarkedExams> listBP = _common.GetBookmarkedExam(user_id, exam_id);

                        if (listBP != null && listBP.Count > 0)
                        {
                            return_message = string.Format("already bookmarked ");
                            return 1; //Its already there, so don't add this one again
                        }
                        else
                        {
                            _context.Database.BeginTransaction();
                            BookmarkedExams be = new BookmarkedExams()
                            {
                                ExamId = exam_id,
                                UserId = user_id,
                                CreatedOn = _common.NowIndianTime(),
                                CreatedBy = user_id,
                                IsActive = true
                            };

                            _context.BookmarkedExams.Add(be);
                            _context.SaveChanges();

                            _context.Database.CommitTransaction();
                        }

                        return_message = string.Format("the exam is bookmarked");
                    }
                    catch (Exception ex)
                    {
                        _context.Database.RollbackTransaction();
                        return_value = -1;
                        return_message = ex.InnerException.ToString();
                    }

                    return 1;
                }


                public int DetachBookmarkFromExams(int user_id, int exam_id, out string return_message)
                {
                    int return_value = 0;

                    try
                    {
                        List<BookmarkedExams> listBE = _common.GetBookmarkedExam(user_id, exam_id);

                        if (listBE == null || listBE.Count == 0)
                        {
                            return_message = string.Format("its not bookmarked ");
                            return 1; //Its already there, so don't add this one again
                        }
                        else
                        {
                            //_context.Database.BeginTransaction();
                            //_context.BookmarkedPractices.Remove(bp);
                            _context.BulkDelete(listBE);

                            //_context.SaveChanges();
                            //_context.Database.CommitTransaction();
                        }

                        return_message = string.Format("the exam is removed");
                    }
                    catch (Exception ex)
                    {
                        _context.Database.RollbackTransaction();
                        return_value = -1;
                        return_message = ex.InnerException.ToString();
                    }

                    return 1;
                }

                public ExamAttemptReportViewModel ViewReportOfTheExam(int institute_id, int language_id, int user_id, int exam_id)
                {
                    ExamAttemptViewModel eav = new ExamAttemptViewModel();
                    ExamAttempts examAttempts = new ExamAttempts();

                    //TBD:Get exam and get user attempts count 
                    //Check if its invalid or inactive or not published or its expired or attempts over

                    ExamAttempts lastAttempt = _context.ExamAttempts.Where(a => a.ExamId == exam_id && a.CreatedBy == user_id 
                    && a.Status == State.COMPLETED).OrderByDescending(a => a.UpdatedOn).FirstOrDefault();

                    if (lastAttempt == null) return null;

                    //TODO: Validity to show the report
                    Exams exam = _context.Exams.Where(e => e.Id == lastAttempt.ExamId).FirstOrDefault();

                    if (exam == null) return null;

                    ExamAttemptReportViewModel qns = _common._examAttempt_getReport(language_id, lastAttempt.Id);

                    return qns;
                }


                public ExamAttemptViewModel GetExamAttemptById(int attempt_id)
                {
                    ExamAttemptViewModel eav = new ExamAttemptViewModel();

                    eav = _common.GetExamAttemptById(attempt_id);

                    return eav;
                }

                public List<ExamAttemptViewModel> GetAllExamAttemptsOfTheExam(int exam_id, int? user_id, bool? isActive, string sortBy, string sortOrder)
                {
                    List<ExamAttemptViewModel> eav = _common.GetAllExamAttemptsOfTheExam(exam_id, user_id, sortBy, sortOrder);

                    return eav;
                }

                public List<ExamAttemptViewModel> GetAllExamAttempts(int? user_id, bool? isActive, string sortBy, string sortOrder)
                {
                    List<ExamAttemptViewModel> eav = _common.GetAllExamAttempts(user_id);

                    if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
                    {
                        if (sortOrder != null && sortOrder.Equals("D"))
                        {
                            switch (sortBy.ToUpper())
                            {
                                case "ID": eav = eav.OrderByDescending(a => a.attempt_id).ToList(); break;
                                case "DATE": eav = eav.OrderByDescending(a => a.attempt_started_on).ToList(); break;
                            }
                        }
                        else
                        {
                            switch (sortBy.ToUpper())
                            {
                                case "ID": eav = eav.OrderBy(a => a.attempt_id).ToList(); break;
                                case "DATE": eav = eav.OrderBy(a => a.attempt_started_on).ToList(); break;
                            }
                        }
                    }

                    return eav;
                }

                public int EndExamAttempt(int user_id, int attempt_id)
                {
                    int returnCode = -1;

                    ExamAttempts attempts = new ExamAttempts();
                    try
                    {
                        //check if the attempt exists and if its created by the user and its not yet completed state
                        attempts = _context.ExamAttempts.Where(a => a.Id == attempt_id && a.Status != State.COMPLETED &&
                                                a.CreatedBy == user_id && a.IsActive == true).FirstOrDefault();

                        if (attempts == null) return returnCode;

                        _context.Database.BeginTransaction();

                        List<ExamAttemptsAnswer> answer = _common.examAttempt_updateAttemptCorrectness(attempts.Id);
                        _context.BulkUpdate(answer);

                        attempts.Score = answer.Sum(a => a.Score);
                        attempts.Status = State.COMPLETED;
                        attempts.RemainingTimeSeconds = 0;
                        attempts.UpdatedOn = _common.NowIndianTime();
                        attempts.UpdatedBy = user_id;
                        _context.Entry(attempts).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                        _context.SaveChanges();
                        _context.Database.CommitTransaction();

                        returnCode = 1;
                    }
                    catch
                    {
                        _context.Database.RollbackTransaction();
                        returnCode = -1;
                    }


                    return returnCode;
                }

                //When paused the paused at time is recoded in DB
                public DurationView PauseExamAttempt(int user_id, int attempt_id)
                {
                    DurationView time = HeartBeat(attempt_id, user_id);

                    try
                    {
                        _context.Database.BeginTransaction();

                        if (time == null || time.time_left <= 0) return time;

                        ExamAttempts attempts = _context.ExamAttempts.Where(a => a.Id == attempt_id).FirstOrDefault();

                        if (attempts.Status == State.START || attempts.Status == State.RESUME) 
                        {
                            attempts.Status = State.PAUSE;
                            attempts.LastPausedAt = _common.NowIndianTime();
                            attempts.RemainingTimeSeconds = time.time_left;
                            attempts.UpdatedOn = _common.NowIndianTime();
                            attempts.UpdatedBy = user_id;

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

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

                    return time;
                }


                public List<ExamAttemptQuestionsViewModel> UpdateExamAttemptQuestion(int user_id, int exam_attempt_id, int question_id)
                {
                    List<ExamAttemptQuestionsViewModel> eaqvm = new List<ExamAttemptQuestionsViewModel>();
                    try
                    {

                        _context.Database.BeginTransaction();
                        //TBD: add Where a.attemptID ==  exam_attempt_id
                        ExamAttemptsAnswer answer = _context.ExamAttemptsAnswer.
                                                    Where(a => a.QuestionId == question_id).
                                                    Where(a => a.IsActive == true).FirstOrDefault();


                        if (answer == null)
                        {
                            answer = new ExamAttemptsAnswer();
                            answer.QuestionId = question_id;
                            answer.UserId = user_id;
                            answer.DateOfAnswer = DateTime.UtcNow;
                            answer.IsActive = true;
                            answer.TimeTakenToAnswerInSeconds = 10000;
                            answer.Comments = "Kuch bhi";
                            answer.StudentAnswer = "MyAnswer";
                            answer.Doubt = "My Doubt";

                            _context.ExamAttemptsAnswer.Add(answer);
                            _context.Entry(answer).State = Microsoft.EntityFrameworkCore.EntityState.Added;

                        }
                        else
                        {
                            //TBD: update with optionids & time, check for changes then update
                            answer.DateOfAnswer = DateTime.UtcNow;
                            answer.TimeTakenToAnswerInSeconds = 10000;
                            answer.Comments = "Kuch bhi";
                            answer.StudentAnswer = "MyAnswer";
                            answer.Doubt = "My Doubt";

                            _context.Entry(answer).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                        }


                        _context.SaveChanges();
                        _context.Database.CommitTransaction();
                    }
                    catch
                    {
                        _context.Database.RollbackTransaction();
                        eaqvm = null;
                    }

                    eaqvm = _common.GetExamAttemptQuestions(exam_attempt_id);

                    return eaqvm;
                }
        */
        #endregion
    }
}
