using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using skydiveLogs_api.DataContract;
using skydiveLogs_api.Domain;
using skydiveLogs_api.DomainBusiness.Interfaces;
using skydiveLogs_api.Settings;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace skydiveLogs_api.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : Base
    {
        #region Public Constructors

        public UserController(IUserService userService,
                              IMapper mapper,
                              IOptions<JwtSettings> jwtSettings)
        {
            _userService = userService;
            _mapper = mapper;
            _jwtConf = jwtSettings.Value;
        }

        #endregion Public Constructors

        #region Public Methods

        // GET: api/User/AlwayLogin
        [HttpGet("AlwaysLogin")]
        [EnableCors]
        public IActionResult AlwaysLogin()
        {
            return Ok();
        }

        // POST: api/User/Authenticate
        [AllowAnonymous]
        [HttpPost("Authenticate")]
        [EnableCors]
        public IActionResult Authenticate([FromBody] UserReq value)
        {
            IActionResult result;
            var foundUser = _userService.GetByLogin(value.Login, value.Password);

            if (foundUser == null)
            {
                result = BadRequest(new { message = "Username or password is incorrect" });
            }
            else
            {
                var resp = _mapper.Map<UserResp>(foundUser);
                resp.Roles = foundUser.IsAdmin ? "admin" : string.Empty;
                resp.Token = CreateToken(resp);

                result = Ok(resp);
            }

            return result;
        }

        // POST: api/User
        [AllowAnonymous]
        [HttpPost]
        [EnableCors]
        public IActionResult Post([FromBody] UserReq userToAdd)
        {
            IActionResult result;
            var newUser = _mapper.Map<User>(userToAdd);

            if (!_userService.AddNewUser(newUser))
            {
                result = BadRequest(new { message = "Error during the creation of the user." });
            }
            else
            {
                var resp = _mapper.Map<UserResp>(newUser);
                resp.Roles = newUser.IsAdmin ? "admin" : string.Empty;
                resp.Token = CreateToken(resp);

                result = Ok(resp);
            }

            return result;
        }

        #endregion Public Methods

        // PUT: api/User/5
        //[HttpPut("{id}")]
        //[EnableCors]
        //public void Put(int id, [FromBody] UserReq value)
        //{
        //    _userService.UpdateUser(id, _mapper.Map<User>(value));
        //}

        #region Private Methods

        private string CreateToken(UserResp foundUser)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtConf.Passphrase));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(issuer: _jwtConf.Issuer,
                                             audience: _jwtConf.Issuer,
                                             expires: DateTime.Now.AddDays(1),
                                             signingCredentials: credentials,
                                             claims: new Claim[]
                                             {
                                                new Claim(ClaimTypes.Name, foundUser.Login),
                                                new Claim(ClaimTypes.UserData, foundUser.Id.ToString()),
                                                new Claim(ClaimTypes.Email, foundUser.Email),
                                                new Claim(ClaimTypes.Role, foundUser.Roles)
                                             });

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        #endregion Private Methods

        #region Private Fields

        private readonly JwtSettings _jwtConf;
        private readonly IMapper _mapper;
        private readonly IUserService _userService;

        #endregion Private Fields
    }
}