using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System.Reflection.Metadata;
using TestMakerFreeWebApp.ViewModels;
using TestMakerFreeWebApp.Data;
using Microsoft.AspNetCore.Identity;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace TestMakerFreeWebApp.Controllers
{
   public class TokenController : BaseApiController
   {
      #region Właościwości prywatne
      #endregion

      #region Konstruktor
      public TokenController(
          ApplicationDbContext context,
          RoleManager<IdentityRole> roleManager,
          UserManager<ApplicationUser> userManager,
          IConfiguration configuration
          )
          : base(context, roleManager, userManager, configuration) { }
      #endregion

      [HttpPost("Auth")]
      public async Task<IActionResult> Auth([FromBody]TokenRequestViewModel model)
      {
         // Zwróć ogólny kod statusu HTTP 500,
         // jeśli dane przesłane przez klienta są niepoprawne
         if (model == null) return new StatusCodeResult(500);

         switch (model.grant_type)
         {
            case "password":
               return await GetToken(model);
            default:
               // Nieobsługiwane, zwróć kod statusu HTTP 401
               return new UnauthorizedResult();
         }
      }

      private async Task<IActionResult> GetToken(TokenRequestViewModel model)
      {
         try
         {
            // Sprawdź, czy istnieje użytkownik o podanej nazwie
            var user = await UserManager.FindByNameAsync(model.username);
            // Dopóść użycie adresu e-mail w zastępstwie nazwy użytkownika
            if (user == null && model.username.Contains("@"))
               user = await UserManager.FindByEmailAsync(model.username);

            if (user == null
                || !await UserManager.CheckPasswordAsync(user, model.password))
            {
               // Użytkownik nie istnieje lub hasła nie pasują do siebie
               return new UnauthorizedResult();
            }

            // Nazwa użytkownika i hasło jest prawidłowe - utwórz token JWT

            DateTime now = DateTime.UtcNow;

            // Dodaj odpowiednie roszczenia do JWT (RFC7519).
            // Więcej informacji znajdziesz pod adresem https://tools.ietf.org/html/rfc7519#section-4.1
            var claims = new[] {
                    new Claim(JwtRegisteredClaimNames.Sub, user.Id),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(JwtRegisteredClaimNames.Iat,
                        new DateTimeOffset(now).ToUnixTimeSeconds().ToString())
                    // NA-PÓŹNIEJ: dodaj dodatkowe roszczenia
                };

            var tokenExpirationMins =
                Configuration.GetValue<int>("Auth:Jwt:TokenExpirationInMinutes");
            var issuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(Configuration["Auth:Jwt:Key"]));

            var token = new JwtSecurityToken(
                issuer: Configuration["Auth:Jwt:Issuer"],
                audience: Configuration["Auth:Jwt:Audience"],
                claims: claims,
                notBefore: now,
                expires: now.Add(TimeSpan.FromMinutes(tokenExpirationMins)),
                signingCredentials: new SigningCredentials(
                    issuerSigningKey, SecurityAlgorithms.HmacSha256)
            );
            var encodedToken = new JwtSecurityTokenHandler().WriteToken(token);

            // Zbuduj i zwróć odpowiedź
            var response = new TokenResponseViewModel()
            {
               token = encodedToken,
               expiration = tokenExpirationMins
            };
            return Json(response);
         }
         catch (Exception ex)
         {
            return new UnauthorizedResult();
         }
      }
   }
}
