using AsbCloudApp.Data;
using AsbCloudApp.Data.User;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudWebApi.Controllers
{
    /// <summary>
    /// Авторизация
    /// </summary>
    [Route("/auth")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private readonly IAuthService authService;
        private readonly IUserRepository userRepository;

        public AuthController(IAuthService authService, IUserRepository userRepository)
        {
            this.authService = authService;
            this.userRepository = userRepository;
        }

        /// <summary>
        /// Аутентификация пользователя
        /// </summary>
        /// <param name="auth"></param>
        /// <param name="token">Токен отмены задачи</param>
        /// <response code="200">новый токен</response>
        /// <response code="400">логин и пароль не подходят</response>
        [AllowAnonymous]
        [HttpPost("login")]
        [SwaggerOperation(OperationId = "login")]
        [ProducesResponseType(typeof(UserTokenDto), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> LoginAsync([FromBody] AuthDto auth, CancellationToken token)
        {
            var userToken = await authService.LoginAsync(auth.Login, auth.Password, token);

            if (userToken is null)
                Forbid();

            return Ok(userToken);
        }

        /// <summary>
        /// Продление срока действия токена
        /// </summary>
        /// <returns code="200">новый токен</returns>
        [Authorize]
        [HttpGet("refresh")]
        [ProducesResponseType(typeof(UserTokenDto), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> RefreshAsync(CancellationToken token)
        {
            var userToken = await authService.RefreshAsync(User, token);

            if (userToken is null)
                Forbid();

            return Ok(userToken);
        }

        /// <summary>
        /// Отправить заявку на регистрацию. Заявка подтверждается администратором.
        /// </summary>
        /// <param name="user">Информация о новом пользователе</param>
        /// <returns code="200">Ок</returns>
        [HttpPost]
        [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
        public IActionResult Register(UserRegistrationDto user)
        {
            authService.Register(user);
            return Ok();
        }

        /// <summary>
        /// Смена пароля пользователя. Доступна пользователю и администратору
        /// </summary>
        /// <returns code="200">Ок</returns>
        [Authorize]
        [HttpPut("{idUser}/ChangePassword")]
        [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
        public IActionResult ChangePassword([FromRoute] int idUser, [FromBody] string newPassword)
        {
            var editorUserId = User.GetUserId();

            if (editorUserId is null)
                return Forbid();

            if (!((editorUserId == idUser) || userRepository.HasPermission((int)editorUserId, "Auth.edit")))
                return Forbid();

            authService.ChangePassword(idUser, newPassword);
            return Ok();
        }
    }
}