using System;
using System.Collections.Generic;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OnlineAssessment.Common;
using OnlineAssessment.Data.EFCore;
using OnlineAssessment.Domain.Models;
using OnlineAssessment.Domain.ViewModels;

namespace OnlineAssessment.V1.Controllers
{
    [Authorize]
    [ApiVersion("1.0")]
    [Route("v{version:apiVersion}")]
    public class PracticesController : BaseController<Practices, EFCorePracticeRepository>
    {
        EFCorePracticeRepository _repository;
        string responseMessage = string.Empty;
        public PracticesController(EFCorePracticeRepository repository) : base(repository)
        {
            _repository = repository;
        }


        
        #region Practices 

        /// <summary>
        /// Add new practice
        /// </summary>
        /// <param name="language"></param>
        /// <param name="class_id"></param>
        /// <param name="newPractice"></param>
        /// <returns></returns>
        [HttpPost("{language}/Classes/{class_id}/Practices")]
        [Authorize(Roles = "Admin")]
        public IActionResult AddNewPractice(string language, int class_id, [FromBody] PracticeAddModel newPractice)
        {
            IActionResult returnResponse = null;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            int language_id = _repository.GetLanguageIdByCode(language);

            string return_message = string.Empty;
            if ((!(ModelState.IsValid)) || (base.InstituteId <= 0) || (language_id <= 0))
            {
                responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }

            else
            {
                PracticeViewModel practice = _repository.AddNewPractice(base.InstituteId, language_id, class_id, user_id, newPractice, out return_message);
                if (practice == null)
                {
                    responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.Practice);
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
                else
                {
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(practice));
                }
            }
            return returnResponse;
        }

        /// <summary>
        /// Delete a practice 
        /// </summary>
        /// <param name="practice_id"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}")]
        [Authorize(Roles = "Admin")]
        public IActionResult DeletePracticeOfTheInstitute(int practice_id)
        {
            IActionResult returnResponse = null;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            int returnResult = _repository.DeletePractice(base.InstituteId, user_id, practice_id);
            if (returnResult <= 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectNotDeleted.ToString(), Constant.Exam);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectDeleteSuccessfully.ToString(), Constant.Exam);
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage));
            }
            return returnResponse;
        }



        /// <summary>
        /// Get Practice details 
        /// </summary>
        /// <param name="practice_id"></param>
        /// <returns></returns>
        [HttpGet("Practices/{practice_id}")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetPracticeByID(int practice_id)
        {
            IActionResult returnResponse;

            PracticeViewModel practice = _repository.GetPracticeById(base.InstituteId, -1, practice_id);
            if (practice == null)
            {
                responseMessage = _repository.GetMessageByCode(Message.NoData.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(practice));
            }
            return returnResponse;
        }

        /// <summary>
        /// Get all upcoming practices of the subject
        /// </summary>
        /// <param name="class_id"></param>
        /// <param name="sortBy"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        [HttpGet("Classes/{class_id}/UpcomingSubjectPractices")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetUpcomingSubjectPractices(int class_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse;
            PracticeViewAllPagedModel practiceListPaged = new PracticeViewAllPagedModel();

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeViewAllModel> theList = _repository.GetUpcomingPractices(base.InstituteId, class_id, -1, Constant.Subject.ToString(), sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeViewAllModel> pList = PaginatedList<PracticeViewAllModel>.CreateAsync(theList, (int)pageNumber, (int)pageSize);
                    practiceListPaged.total_count = theList.Count;
                    practiceListPaged.total_pages = pList.TotalPages;
                    practiceListPaged.page_index = pList.PageIndex;
                    practiceListPaged.next = pList.HasNextPage;
                    practiceListPaged.previous = pList.HasPreviousPage;
                    practiceListPaged.practices = pList;
            }
            
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(practiceListPaged));
            
            return returnResponse;
        }

        /// <summary>
        /// Get all upcoming practices of the category
        /// </summary>
        /// <param name="class_id"></param>
        /// <param name="sortBy"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        [HttpGet("Classes/{class_id}/UpcomingCategoryPractices")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetUpcomingCategoryPractices(int class_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse;
            PracticeViewAllPagedModel practiceListPaged = new PracticeViewAllPagedModel();

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeViewAllModel> theList = _repository.GetUpcomingPractices(base.InstituteId, class_id, -1, Constant.Category.ToString(), sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeViewAllModel> pList = PaginatedList<PracticeViewAllModel>.CreateAsync(theList, (int)pageNumber, (int)pageSize);
                    practiceListPaged.total_count = theList.Count;
                    practiceListPaged.total_pages = pList.TotalPages;
                    practiceListPaged.page_index = pList.PageIndex;
                    practiceListPaged.next = pList.HasNextPage;
                    practiceListPaged.previous = pList.HasPreviousPage;
                    practiceListPaged.practices = pList;
            }
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(practiceListPaged));
            
            return returnResponse;
        }


        /// <summary>
        /// Get all Live practices 
        /// </summary>
        /// <param name="class_id"></param>
        /// <param name="sortBy"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        [HttpGet("Classes/{class_id}/LiveSubjectPractices")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetLiveSubjectPractices(int class_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse;
            PracticeViewAllPagedModel practiceListPaged = new PracticeViewAllPagedModel();

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeViewAllModel> theList = _repository.GetLivePractices(base.InstituteId, class_id, -1, Constant.Subject.ToString(), sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeViewAllModel> pList = PaginatedList<PracticeViewAllModel>.CreateAsync(theList, (int)pageNumber, (int)pageSize);
                    practiceListPaged.total_count = theList.Count;
                    practiceListPaged.total_pages = pList.TotalPages;
                    practiceListPaged.page_index = pList.PageIndex;
                    practiceListPaged.next = pList.HasNextPage;
                    practiceListPaged.previous = pList.HasPreviousPage;
                    practiceListPaged.practices = pList;
            }
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(practiceListPaged));
            
            return returnResponse;
        }


        /// <summary>
        /// Get all Live practices 
        /// </summary>
        /// <param name="class_id"></param>
        /// <param name="sortBy"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        [HttpGet("Classes/{class_id}/LiveCategoryPractices")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetLiveCategoryPractices(int class_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse;
            PracticeViewAllPagedModel practiceListPaged = new PracticeViewAllPagedModel();

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeViewAllModel> theList = _repository.GetLivePractices(base.InstituteId, class_id, -1, Constant.Category.ToString(), sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeViewAllModel> pList = PaginatedList<PracticeViewAllModel>.CreateAsync(theList, (int)pageNumber, (int)pageSize);
                    practiceListPaged.total_count = theList.Count;
                    practiceListPaged.total_pages = pList.TotalPages;
                    practiceListPaged.page_index = pList.PageIndex;
                    practiceListPaged.next = pList.HasNextPage;
                    practiceListPaged.previous = pList.HasPreviousPage;
                    practiceListPaged.practices = pList;
            }
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(practiceListPaged));
            
            return returnResponse;
        }


        /// <summary>
        /// Get all draft practices 
        /// </summary>
        /// <param name="class_id"></param>
        /// <param name="sortBy"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        [HttpGet("Classes/{class_id}/DraftSubjectPractices")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetDraftSubjectPractices(int class_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse;
            PracticeViewAllPagedModel practiceListPaged = new PracticeViewAllPagedModel();

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeViewAllModel> theList = _repository.GetDraftPractices(base.InstituteId, class_id, -1, Constant.Subject.ToString(), sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeViewAllModel> pList = PaginatedList<PracticeViewAllModel>.CreateAsync(theList, (int)pageNumber, (int)pageSize);
                    practiceListPaged.total_count = theList.Count;
                    practiceListPaged.total_pages = pList.TotalPages;
                    practiceListPaged.page_index = pList.PageIndex;
                    practiceListPaged.next = pList.HasNextPage;
                    practiceListPaged.previous = pList.HasPreviousPage;
                    practiceListPaged.practices = pList;
            }
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(practiceListPaged));
            
            return returnResponse;
        }

        /// <summary>
        /// Get all draft practices 
        /// </summary>
        /// <param name="class_id"></param>
        /// <param name="sortBy"></param>
        /// <param name="sortOrder"></param>
        /// <returns></returns>
        [HttpGet("Classes/{class_id}/DraftCategoryPractices")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetDraftCategoryPractices(int class_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse;
            PracticeViewAllPagedModel practiceListPaged = new PracticeViewAllPagedModel();

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeViewAllModel> theList = _repository.GetDraftPractices(base.InstituteId, class_id, -1, Constant.Category.ToString(), sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeViewAllModel> pList = PaginatedList<PracticeViewAllModel>.CreateAsync(theList, (int)pageNumber, (int)pageSize);
                    practiceListPaged.total_count = theList.Count;
                    practiceListPaged.total_pages = pList.TotalPages;
                    practiceListPaged.page_index = pList.PageIndex;
                    practiceListPaged.next = pList.HasNextPage;
                    practiceListPaged.previous = pList.HasPreviousPage;
                    practiceListPaged.practices = pList;
            }
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(practiceListPaged));
            
            return returnResponse;
        }

        /// <summary>
        /// Attach Questions To Practices
        /// </summary>
        /// <param name="practice_id"></param>
        /// <param name="questionIdList"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}/AttachQuestions")]
        [Authorize(Roles = "Admin")]
        public IActionResult AttachQuestionsToPractice(int practice_id, [FromBody] QuestionsList questionIdList)
        {
            IActionResult returnResponse = null;
            string return_message = string.Empty;
            if (questionIdList == null || questionIdList.idList == null || questionIdList.idList.Count == 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                int recordsEffected = _repository.AttachQuestionsToPractice(base.InstituteId, -1, practice_id, questionIdList, out return_message);
                if (recordsEffected == 0)
                {
                    responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString());
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
                else
                {
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(return_message));
                }
            }
            return returnResponse;
        }

        /// <summary>
        /// Detach Questions from Practice
        /// </summary>
        /// <param name="practice_id"></param>
        /// <param name="questionIdList"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}/DetachQuestions")]
        [Authorize(Roles = "Admin")]
        public IActionResult DetachQuestionsFromPractice(int practice_id, [FromBody] QuestionsList questionIdList)
        {
            IActionResult returnResponse = null;
            string return_message = string.Empty;
            if (questionIdList == null || questionIdList.idList == null || questionIdList.idList.Count == 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                int recordsEffected = _repository.DetachQuestionsFromPractice(base.InstituteId, practice_id, questionIdList, out return_message);
                if (recordsEffected < 0)
                {
                    responseMessage = _repository.GetMessageByCode(Message.FailedToDetach.ToString());
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
                else
                {
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(return_message));
                }
            }
            return returnResponse;
        }

        /// <summary>
        /// Get all questions
        /// </summary>
        /// <param name="practice_id"></param>
        /// <returns></returns>
        [HttpGet("Practices/{practice_id}/Questions")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetQuestionsOfThePractice(int practice_id, [FromQuery] string sortBy, string sortOrder, [FromQuery] int? pageNumber, [FromQuery] int? pageSize)
        {
            IActionResult returnResponse = null;
            string return_message = string.Empty;
            PracticeQuestionsPagedModel qnsListPaged = new PracticeQuestionsPagedModel();
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            if (pageNumber == null) pageNumber = 1;
            if (pageSize == null) pageSize = 20;

            List<PracticeQuestionDetails> qnsList = _repository.GetQuestionsOfThePractice(base.InstituteId, user_id, practice_id, sortBy, sortOrder);

            if (pageNumber != null && pageSize != null)
            {
                    PaginatedList<PracticeQuestionDetails> pList = PaginatedList<PracticeQuestionDetails>.CreateAsync(qnsList, (int)pageNumber, (int)pageSize);
                    qnsListPaged.total_count = qnsList.Count;
                    qnsListPaged.total_pages = pList.TotalPages;
                    qnsListPaged.page_index = pList.PageIndex;
                    qnsListPaged.next = pList.HasNextPage;
                    qnsListPaged.previous = pList.HasPreviousPage;
                    qnsListPaged.questions = pList;
            }
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(qnsListPaged));
            
            return returnResponse;
        }

        /// <summary>
        /// Review Questions Of The Practice
        /// </summary>
        /// <param name="practice_id"></param>
        /// <param name="questionList"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}/ReviewQuestions")]
        [Authorize(Roles = "Admin")]
        public IActionResult AssignDurationToPracticeQuestions(int practice_id, [FromBody] QuestionDurationList questionList)
        {
            IActionResult returnResponse = null;

            PracticeViewModel practice = _repository.AssignDurationToPracticeQuestions(base.InstituteId, practice_id, questionList);
            if (practice == null)
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectNotUpdated.ToString(), Constant.Practice);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(practice));
            }
            return returnResponse;
        }

        /// <summary>
        /// Publish Practice  
        /// </summary>
        /// <param name="practice_id"></param>
        /// <param name="schedulePractice"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}/Publish")]
        [Authorize(Roles = "Admin")]
        public IActionResult PublishPractice(int practice_id, [FromBody] PracticePublishModel schedulePractice)
        {
            IActionResult returnResponse = null;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            PracticeViewModel practice = _repository.PublishPractice(base.InstituteId, user_id, practice_id, schedulePractice);
            if (practice == null)
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectNotUpdated.ToString(), Constant.Practice);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(practice));
            }
            return returnResponse;
        }

        /// <summary>
        /// Attach usergroups to Exam  
        /// </summary>
        /// <param name="practice_id"></param>
        /// <param name="batchList"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}/AttachBatch")]
        [Authorize(Roles = "Admin")]
        public IActionResult AttachBatchToThePractice(int practice_id, [FromBody] UserGroupsList batchList)
        {
            IActionResult returnResponse = null;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            int groups_added = _repository.AttachUserGroups(base.InstituteId, user_id, practice_id, batchList);
            if (groups_added <= 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString(), Constant.Practice);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(groups_added));
            }
            return returnResponse;
        }


        /// <summary>
        /// Detach usergroups to Exam  
        /// </summary>
        /// <param name="practice_id"></param>
        /// <param name="batchList"></param>
        /// <returns></returns>
        [HttpPost("Practices/{practice_id}/DetachBatch")]
        [Authorize(Roles = "Admin")]
        public IActionResult DetachBatchToThePractice(int practice_id, [FromBody] UserGroupsList batchList)
        {
            IActionResult returnResponse = null;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            int groups_added = _repository.DetachUserGroups(base.InstituteId, user_id, practice_id, batchList);
            if (groups_added <= 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString(), Constant.Practice);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(groups_added));
            }
            return returnResponse;
        }

        /// <summary>
        /// Get usergroups attached to Practice  
        /// </summary>
        /// <param name="exam_id"></param>
        /// <returns></returns>
        [HttpGet("Practices/{practice_id}/Batches")]
        [Authorize(Roles = "Admin")]
        public IActionResult GetBatchListOfThePractice(int practice_id)
        {

            IActionResult returnResponse = null;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            UserGroupsList ugl = _repository.GetBatchListsOfThePractice(base.InstituteId, user_id, practice_id);
            
            returnResponse = Ok(ReturnResponse.GetSuccessStatus(ugl));
            
            return returnResponse;
        }

        
        #endregion
        

    }
}
