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

namespace OnlineAssessment.V2.Controllers
{
    [Route("v{version:apiVersion}/[controller]")]
    [ApiController]
    [ApiVersion("2.0")]
    public class UsersController : BaseController<Users, EfCoreUserRepository>
    {
        private readonly IConfiguration _config;
        EfCoreUserRepository _repository;
        string responseMessage;
        public UsersController(EfCoreUserRepository repository, IConfiguration config) : base(repository)
        {
            _repository = repository;
            _config = config;
        }

/*
        /// <summary>
        /// Create a new user
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public IActionResult SignUp([FromBody] UserAddModel user)
        {
            int returnCode = 0;
            string returnMessage = string.Empty;
            IActionResult returnResponse;
            UserViewModel newUser = _repository.SignUp(user, out returnCode, out returnMessage);
            if (newUser != null)
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(newUser as dynamic));
            else
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage + " " + returnMessage));
            }

            return returnResponse;
        }

        /// <summary>
        /// User Log in 
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("[Action]")]
        [Authorize]
        public async System.Threading.Tasks.Task<IActionResult> SignIn()
        {
            string returnMessage = string.Empty;
            IActionResult returnResponse;

            ClaimsIdentity identity = HttpContext.User.Identity as ClaimsIdentity;
            string uuid = Security.GetValueFromToken("user_id", identity);

            LoginViewModel login = _repository.SignUpStudent(identity, out returnMessage);
            if(login != null)
            {
                string token = await Security.GetFirebaseTokenAsync(uuid, login.id, login.role_id);
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(login));
            }
                
            else
            {
                responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage + " " + returnMessage));
            }

            return returnResponse;
        }
*/

        /// <summary>
        /// Admin/ Teacher Log in 
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("[Action]")]
        [Authorize]
        public async System.Threading.Tasks.Task<IActionResult> SignIn()
        {
            string returnMessage = string.Empty;
            IActionResult returnResponse;

            ClaimsIdentity identity = HttpContext.User.Identity as ClaimsIdentity;
            string uuid = Security.GetValueFromToken("user_id", identity);

            dynamic login = _repository.SignInAdminTeacher(identity, out returnMessage);
            if (login is LoginViewModel)
            {
                string token = await Security.GetFirebaseTokenAsync(uuid, login.id, login.role_id, 1);
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(login));
            }
            else if (login is int && login == (int)UserMessage.InvalidUser)
            {
                responseMessage = _repository.GetMessageByCode(UserMessage.InvalidUser.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.InvalidUser, responseMessage));
            }
            else if (login is int && login == (int)Message.NotAllowedToResource)
            {
                responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.NotAllowedToResource, responseMessage));
            }
            else
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToSignIn.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.FailedToAdd, responseMessage));
            }


            return returnResponse;
        }


        /// <summary>
        /// Add Admin/Teacher
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("[Action]")]
        [Authorize(Roles = "Admin")]
        public IActionResult AddAdminTeacher([FromBody] AddAdminTeacherModel userDetails)
        {
            string returnMessage = string.Empty;
            IActionResult returnResponse;

            if (userDetails == null || (userDetails.roleId != 2 && userDetails.roleId != 3))
            {
                responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString());
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus(responseMessage));
            }
            
            dynamic login = _repository.AddAdminTeacher(InstituteId, userDetails.emailId, userDetails.roleId, out returnMessage);
            
            if (login is LoginViewModel)
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(login.email_id));
            }                
            else if(login is int && login == (int)UserMessage.InvalidUser)
            {
                responseMessage = _repository.GetMessageByCode(UserMessage.InvalidUser.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.InvalidUser, responseMessage));
            }
            else if(login is int && login == (int)Message.NotAllowedToResource)
            {
                responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.NotAllowedToResource, responseMessage));
            }
            else if (login is int && login == (int)UserMessage.UserAlreadyExists)
            {
                responseMessage = _repository.GetMessageByCode(UserMessage.UserAlreadyExists.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.UserAlreadyExists, responseMessage));
            }
            else
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToAdd.ToString(), Constant.User);
                returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.FailedToAdd, responseMessage));
            }

            return returnResponse;
        }

       /* 
        /// <summary>
        /// User Log in 
        /// </summary>
        /// <param name="loginCredentials"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [Route("[Action]")]
        public IActionResult SignIn([FromBody] UserLogin loginCredentials)
        {
            int returnCode = 0;
            IActionResult returnResponse;
            LoginViewModel loggedOnUser = _repository.SignIn(loginCredentials, out returnCode);
            if (loggedOnUser != null && returnCode > 0)
            {
                //Generate and set the access token
                var secretKey = _config["Jwt:Key"].ToString();
                var issuer = _config["Jwt:Issuer"].ToString();
                var audience = _config["Jwt:Issuer"].ToString();

                //-----------------------------------------------------------------------------------------------
                loggedOnUser.JwtToken = Security.GetJwtToken(loggedOnUser, secretKey, issuer, audience);
                //-----------------------------------------------------------------------------------------------

                returnResponse = Ok(ReturnResponse.GetSuccessStatus(loggedOnUser as dynamic));
            }
            else
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToSignIn.ToString());
                switch (returnCode)
                {
                    case (int)UserMessage.InvalidUser:
                        responseMessage = string.Concat(responseMessage, ". Reason: ", _repository.GetMessageByCode(UserMessage.InvalidUser.ToString()));
                        break;
                    case (int)UserMessage.InvalidPasword:
                        responseMessage = string.Concat(responseMessage, ". Reason: ", _repository.GetMessageByCode(UserMessage.InvalidPasword.ToString()));
                        break;
                    case (int)UserMessage.UserNotActive:
                        responseMessage = string.Concat(responseMessage, ". Reason:", _repository.GetMessageByCode(UserMessage.UserNotActive.ToString()));
                        break;
                }

                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }


            return returnResponse;
        }
        */




        /// <summary>
        /// Edit an user (accessible to SuperAdmin only)
        /// </summary>
        /// <param name="id">The id of the user to edit</param>
        /// <param name="userEdit">User's data to edit</param>
        /// <returns></returns>
        [HttpPost("{id}")]
        [Authorize(Roles = "SuperAdmin")]
        public IActionResult Put(int id, [FromBody] UserEditModel userEdit)
        {
            IActionResult returnResponse = null;
            if (id != userEdit.Id)
            {
                responseMessage = _repository.GetMessageByCode(Message.IdMismatchBetweenBodyAndQueryString.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                return returnResponse;
            }
            else
            {
                string returnMessage = string.Empty;
                UserViewModel uvm = _repository.UpdateUser(id, userEdit, out returnMessage);
                if (uvm != null)
                {
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(uvm));
                }
                else
                {
                    responseMessage = _repository.GetMessageByCode(Message.ObjectNotUpdated.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(new List<string> { responseMessage, returnMessage }));
                }
            }
            return returnResponse;
        }

        /// <summary>
        /// Delete a record (accessible to SuperAdmin only)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost("{id}")]
        [Authorize(Roles = "SuperAdmin")]
        public IActionResult Delete(int id)
        {
            IActionResult returnResponse = null;
            try
            {
                bool isSuccess = _repository.Delete(id);
                if (isSuccess)
                {
                    responseMessage = _repository.GetMessageByCode(Message.SucessfullyDeleted.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage));
                }
                else
                {
                    responseMessage = _repository.GetMessageByCode(Message.ObjectNotDeleted.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
            }
            catch (Exception ex)
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectNotDeleted.ToString(), Constant.User);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(new List<string> { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() }));
            }
            return returnResponse;
        }

        [HttpPost]
        [AllowAnonymous]
        [Route("RegUser")]
        public IActionResult RegisterUser(StudentAddModel data)
        {
            int returnCode = -1;
            string returnMessage = string.Empty;
            IActionResult returnResponse = null;
            int userID = -1;
            try
            {
                userID = _repository.RegisterUser(data, out returnCode, out returnMessage);
                if(userID > 0)
                {
                    responseMessage = _repository.GetMessageByCode(Message.SucessfullyAdded.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage));
                }
                else if(userID == (int)UserMessage.UserAlreadyExists)
                {
                    responseMessage = _repository.GetMessageByCode(UserMessage.UserAlreadyExists.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
                else
                {
                    responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
            }
            catch (ApplicationException ex)
            {
                responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(new List<string> { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() }));
            }

            return returnResponse;
        }

        [HttpGet]
        [AllowAnonymous]
        [Route("VerifyAccount/{code}")]
        public IActionResult ActivateUser(string code)
        {
            string returnMessage = string.Empty;
            IActionResult returnResponse = null;
            int userID = -1;
            try
            {
                userID = _repository.VerifyAccount(code, out returnMessage);
                if (userID > 0)
                {
                    responseMessage = _repository.GetMessageByCode(Message.Success.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage));
                }
                else
                {
                    responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User);
                    returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
                }
            }
            catch (ApplicationException ex)
            {
                responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User);
                returnResponse = Ok(ReturnResponse.GetFailureStatus(new List<string> { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() }));
            }

            return returnResponse;
        }



        /// <summary>
        /// Update language
        /// </summary>
        /// <param name="language"></param>
        /// <returns></returns>
        [HttpPost("{language}/UpdatePreference")]
        [Authorize(Roles = "Student")]
        public IActionResult UpdatePreference(string language)
        {
            IActionResult returnResponse = null;
            string return_message = string.Empty;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            int language_id = _repository.GetLanguageIdByCode(language);

            if (language_id <= 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.NoData.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }

            //TODO: check if works fine
            int langId = _repository.UpdateMyLanguage(user_id, language_id, out return_message);
            if (langId < 0)
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(return_message));
            }

            return returnResponse;
        }


        /// <summary>
        /// Attch me to usergroup
        /// </summary>
        /// <param name="user_group_id"></param>
        /// <param name="defaultGroup"></param>
        /// <returns></returns>
        [HttpPost("{user_group_id}/AttachBatch")]
        [Authorize(Roles = "Student")]
        public IActionResult AttachMeToUserGroup(int user_group_id, [FromBody] DefaultGroup defaultGroup)
        {
            IActionResult returnResponse = null;
            string return_message = string.Empty;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            //TODO: check if works fine
            ClassStructureViewModel csvm = _repository.AttachMeToUserGroup(base.InstituteId, user_group_id, user_id, defaultGroup.isDefault, out return_message);
            if (csvm == null)
            {
                responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString());
                returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage));
            }
            else
            {
                returnResponse = Ok(ReturnResponse.GetSuccessStatus(csvm));
            }

            return returnResponse;
        }

        /// <summary>
        /// Detach user group of a user
        /// </summary>
        /// <param name="user_group_id"></param>
        /// <returns></returns>
        [HttpPost("{user_group_id}/Detach")]
        [Authorize(Roles = "Admin,Teacher,Student")]
        public IActionResult DetachUserGroup(int user_group_id)
        {
            IActionResult returnResponse = null;
            string return_message = string.Empty;
            int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity);

            int recordsEffected = _repository.DetachUserGroup(base.InstituteId, user_id, user_group_id, 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;
        }
    }
}
