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 EFCoreExamAttemptRepository : EfCoreRepository<ExamAttempts, OnlineAssessmentContext>
    {
        public readonly OnlineAssessmentContext _context;
        public readonly EfCoreCommonRepository _common;
        private readonly IMapper _mapper;
        public EFCoreExamAttemptRepository(OnlineAssessmentContext context, IMapper mapper, IOptionsSnapshot<ResponseMessage> responseMessage) : base(context, responseMessage)
        {
            _context = context;
            _mapper = mapper;
            _common = new EfCoreCommonRepository(_context, mapper);
        }


        #region ExamAttempts

        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 bool isValidBatch(int institute_id, int batch_id, int user_id)
        {
            return _common.isValidBatch(institute_id, batch_id, user_id);
        }

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

        //Student : Getting upcoming exams of an batch
        public dynamic GetUpcomingExamsOfTheBatch(int institute_id, int batch_id, int user_id, string sortBy, string sortOrder)
        {
            List<ExamAttemptAllExamModel> examDetailList = new List<ExamAttemptAllExamModel>();

            try
            {
                if (_common.isValidBatch(institute_id, batch_id, user_id) == false)
                    return (int)Message.NotAllowedToResource;

                
                List<Exams> examsList = (from uge in _context.UserGroupExams
                                         join e in _context.Exams on uge.ExamId equals e.Id

                                         where uge.UserGroupId == batch_id && uge.IsActive == true
                                         && e.InstituteId == institute_id && e.ExamOpenDatetime > _common.NowIndianTime() && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.IsActive == true

                                         select e).ToList();

                if (examsList == null || examsList.Count == 0) return (int)Message.NoData;

                examDetailList = _common.GetExamDetailsByIds(institute_id, batch_id, user_id, examsList);

                if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
                {
                    if (sortOrder != null && sortOrder.Equals("D"))
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "ID": examDetailList = examDetailList.OrderByDescending(a => a.id).ToList(); break;
                            case "DATE": examDetailList = examDetailList.OrderByDescending(a => a.start_date).ToList(); break;
                        }
                    }
                    else
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "ID": examDetailList = examDetailList.OrderBy(a => a.id).ToList(); break;
                            case "DATE": examDetailList = examDetailList.OrderBy(a => a.start_date).ToList(); break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                return (int)Message.Failure; 
            }

            return examDetailList;
        }

        //Student: Getting ongoing exams of an institute
        public dynamic GetLiveExamsBySubject(int institute_id, int batch_id, int user_id, int subject_id, string sortBy, string sortOrder)
        {
            List<ExamAttemptAllExamModel> examDetailList = new List<ExamAttemptAllExamModel>();

            try
            {
                if (_common.isValidBatch(institute_id, batch_id, user_id) == false)
                    return (int)Message.NotAllowedToResource;

                List<Exams> examsList = (from uge in _context.UserGroupExams
                                         join e in _context.Exams on uge.ExamId equals e.Id

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

                                          select e).ToList();

                if (examsList == null || examsList.Count == 0) return null;

                examDetailList = _common.GetExamDetailsByIds(institute_id, batch_id, user_id, examsList);

                if (subject_id > 0)
                    examDetailList = examDetailList.Where(e => e.subject_count == 1 && e.subject_id == subject_id).ToList();
                else if (subject_id == 0)
                    examDetailList = examDetailList.Where(e => e.subject_count > 1).ToList();

                if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
                {
                    if (sortOrder != null && sortOrder.Equals("D"))
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "DATE": examDetailList = examDetailList.OrderByDescending(a => a.updated_on).ToList(); break;
                            case "AUTHOR": examDetailList = examDetailList.OrderByDescending(a => a.author_name).ToList(); break;
                        }
                    }
                    else
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "DATE": examDetailList = examDetailList.OrderBy(a => a.updated_on).ToList(); break;
                            case "AUTHOR": examDetailList = examDetailList.OrderBy(a => a.author_name).ToList(); break;
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                return (int)Message.Failure;
            }

            return examDetailList;
        }

        //Student: Getting ongoing exams of an institute by author
        public dynamic GetLiveExamsByAuthor(int institute_id, int batch_id, int user_id, int author_id, int subject_id, string sortBy, string sortOrder)
        {
            List<ExamAttemptAllExamModel> examDetailList = new List<ExamAttemptAllExamModel>();

            try
            {
                if (_common.isValidBatch(institute_id, batch_id, user_id) == false)
                    return (int)Message.NotAllowedToResource;


                List<Exams> examsList = (from uge in _context.UserGroupExams
                                         join e in _context.Exams on uge.ExamId equals e.Id

                                         where uge.UserGroupId == batch_id && uge.IsActive == true
                                         && e.InstituteId == institute_id && e.ExamOpenDatetime < _common.NowIndianTime() && e.ExamCloseDatetime > _common.NowIndianTime() && e.ExamStatus == StatusCode.PUBLISHED.ToString() && e.IsActive == true
                                         && e.CreatedBy == author_id

                                         select e).ToList();

                if (examsList == null || examsList.Count == 0) return null;

                examDetailList = _common.GetExamDetailsByIds(institute_id, batch_id, user_id, examsList);

                //if subject_id < 0 i.e -1 then all exams will be displayed
                if (subject_id > 0)
                    examDetailList = examDetailList.Where(e => e.subject_count == 1 && e.subject_id == subject_id).ToList();
                else if (subject_id == 0)
                    examDetailList = examDetailList.Where(e => e.subject_count > 1).ToList();

                if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
                {
                    if (sortOrder != null && sortOrder.Equals("D"))
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "ID": examDetailList = examDetailList.OrderByDescending(a => a.id).ToList(); break;
                            case "AUTHOR": examDetailList = examDetailList.OrderByDescending(a => a.author_name).ToList(); break;
                        }
                    }
                    else
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "ID": examDetailList = examDetailList.OrderBy(a => a.id).ToList(); break;
                            case "AUTHOR": examDetailList = examDetailList.OrderBy(a => a.author_name).ToList(); break;
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                return (int)Message.Failure;
            }

            return examDetailList;
        }

        //Student: Getting attempted exams of an institute
        public dynamic GetAttemptedExams(int institute_id, int batch_id, int user_id, string sortBy, string sortOrder)
        {
            List<ExamAttemptAttemptedExamModel> examList = new List<ExamAttemptAttemptedExamModel>();

            try
            {
                examList = _common.GetAttemptedExamList(institute_id, batch_id, user_id);

                if (examList == null || examList.Count == 0) return (int)Message.NoData;

                if ((sortOrder != null && sortOrder.Length > 0) || (sortBy != null && sortBy.Length > 0))
                {
                    if (sortOrder != null && sortOrder.Equals("D"))
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "DATE": examList = examList.OrderByDescending(a => a.attempted_on).ToList(); break;
                            case "AUTHOR": examList = examList.OrderByDescending(a => a.author_name).ToList(); break;
                        }
                    }
                    else
                    {
                        switch (sortBy.ToUpper())
                        {
                            case "DATE": examList = examList.OrderBy(a => a.attempted_on).ToList(); break;
                            case "AUTHOR": examList = examList.OrderBy(a => a.author_name).ToList(); break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                return (int)Message.Failure;
            }
            
            return examList;
        }

        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 <= -10 || exams.ExamCloseDatetime < _common.NowIndianTime())
            {
                EndExamAttempt(user_id, attempts.Id);

                time.time_left = 0;
                return time;
            }

            time.time_left = attempts.RemainingTimeSeconds;

            return time;
        }

        public dynamic UpdateAnswer(int attempt_id, int user_id, QuestionAnswerViewModel responses)
        {
            DurationView time = HeartBeat(attempt_id, user_id);
            if (time == null || time.time_left <= 0) return (int)Message.NotAllowedToResource;

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

            if (responses == null)
            {
                return (int)Message.InvalidInput;
            }

            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 (int osvm in responses.answers)
                        {
                            strAns.Add(osvm.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 (int osvm in responses.answers)
                    {
                        strAns.Add(osvm.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();
                return (int)Message.Failure;
            }

            return time;
        }

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

            try
            {
                //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.NotAllowedToResource;

                details.exam_id = exam.Id;
                details.exam_name = exam.Name;
                details.exam_instruction = exam.Instruction;
                details.total_time = (int)exam.ExamDurationInSeconds;
                details.total_likes = _context.BookmarkedExams.Where(b => b.ExamId == exam_id && b.IsActive == true).ToList().Count; ;
                details.author_id = exam.CreatedBy;
                details.points_needed = 0;
                details.attempts_allowed = (int)exam.AttemptsAllowed;

                /* SUBSDELETE
                SubscriptionViewModel svm = _common.mySubscriptionDetails(user_id);
                if(svm == null)
                {
                    details.points_available = 0;
                    details.isSubscribed = false;
                }
                else
                {
                    details.points_available = svm.remaining_exam_credits;
                    SubscribedExams subsExam = _context.SubscribedExams.Where(se => se.SubscriptionId == svm.id && se.ExamId == exam_id && se.IsActive == true).FirstOrDefault();
                    details.isSubscribed = subsExam != null ? true : false;
                }
                */
                details.points_available = 1;
                details.isSubscribed = true;
                

                List <ExamAttempts> allAttempts = _context.ExamAttempts.Where(a => a.ExamId == exam_id && a.IsActive == true).ToList();
                List<ExamAttempts> myAttempts;
                if (allAttempts == null || allAttempts.Count == 0)
                {
                    details.total_plays = 0;
                    details.attempts_completed = 0;
                }
                else
                {
                    details.total_plays = allAttempts.Select(l => l.CreatedBy).Distinct().Count();
                    myAttempts = allAttempts.Where(l => l.CreatedBy == user_id).ToList();
                    details.attempts_completed = myAttempts != null ? myAttempts.Count() : 0;
                }

                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;
                    }
                }
            }
            catch(Exception ex)
            {
                return (int)Message.Failure;
            }
            
            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;

            try
            {
                //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.NotAllowedToResource;
                }

                /*
                //Check subscription validity
                SubscriptionViewModel svm;
                int subscription_id = 0;
                bool isSubscribed = false;
                if(exam.CreditsNeeded > 0)
                {
                    svm = _common.mySubscriptionDetails(user_id);
                    if (svm == null)
                        return (int)Message.NoValidSubscription;

                    subscription_id = svm.id;

                    SubscribedExams subsExam = _context.SubscribedExams.Where(se => se.SubscriptionId == svm.id
                                        && se.ExamId == exam_id && se.IsActive == true).FirstOrDefault();
                    
                    if(subsExam == null && svm.remaining_exam_credits < exam.CreditsNeeded)
                    {
                        return (int)Message.NoValidSubscription;
                    }
                    if (subsExam != null)
                        isSubscribed = true;
                }
                */

                //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 (int)Message.Failure;
                    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.UpdatedBy = user_id;
                    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); 
                }

                return (int)Message.Failure;
            }
            catch(Exception ex)
            {
                return (int)Message.Failure;
            }
            
        }

        public int AttachBookmarkToExams(int institute_id, int batch_id, int user_id, int exam_id)
        {
            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 (int)Message.NotAllowedToResource;
                }

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

                if (listBP != null && listBP.Count > 0)
                {
                    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();
                }

            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return (int)Message.Failure;
            }

            return 1;
        }


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

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

                if (listBE == null || listBE.Count == 0)
                {
                    return 1; //Its already there, so don't add this one again
                }
                else
                {
                    _context.BulkDelete(listBE);
                }
            }
            catch (Exception ex)
            {
                _context.Database.RollbackTransaction();
                return (int)Message.Failure;
            }

            return 1;
        }

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

            ExamAttempts lastAttempt = _context.ExamAttempts.Where(a => a.Id == exam_attempt_id 
                                        && a.CreatedBy == user_id).OrderByDescending(a => a.UpdatedOn).FirstOrDefault();

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

            if (lastAttempt.Status != State.COMPLETED) return (int)Message.NotAllowedToResource;

            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 (int)Message.InvalidInput;

                _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 = (int)Message.Failure;
            }


            return returnCode;
        }

        //When paused the paused at time is recoded in DB
        public dynamic PauseExamAttempt(int user_id, int attempt_id)
        {
            DurationView time = HeartBeat(attempt_id, user_id);
            if (time == null || time.time_left <= 0) return (int)Message.NotAllowedToResource;

            try
            {
                _context.Database.BeginTransaction();

                ExamAttempts attempts = _context.ExamAttempts.Where(a => a.Id == attempt_id).FirstOrDefault();
                if (attempts.CreatedBy != user_id) return (int)Message.InvalidInput;
                if(attempts.Status == State.COMPLETED) return (int)Message.InvalidInput;

                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 (int)Message.Failure;
            }

            return time;
        }

        public dynamic GetExamAttemptQuestions(int language_id, int user_id, int exam_attempt_id)
        {
            try
            {
                ExamAttempts ea = _context.ExamAttempts.Where(a => a.Id == exam_attempt_id && a.CreatedBy == user_id && a.IsActive == true).FirstOrDefault();
                if (ea == null)
                {
                    return (int)Message.InvalidInput;
                }

                ExamAttemptAllQuestionsViewModel q = _common.GetExamAttemptQuestions(language_id, exam_attempt_id);
                if (q == null) return (int)Message.NoData;

                return q;
            }
            catch (Exception ex)
            {
                return (int)Message.Failure;
            }           
        }
/*
        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
    }
}
