using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
using System.Text;
using Kafka.Lib.Auth;
using MassTransit;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using OpenWarehouse.auth.api.Common.AuthTokenRepo;
using OpenWarehouse.auth.api.Common.CustomIdentifyManager;
using OpenWarehouse.auth.api.Common.ServiceManager;
using OpenWarehouse.auth.lib.Model.Service;

namespace OpenWarehouse.auth.api.Controller;

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("[controller]/[action]")]
public class Service(
    UserManager<ApplicationUser> userManager,
    IConfiguration configuration, AuthTokenRepo tokenRepo,
    IServiceManager serviceManager, ILogger<Service> logger,
    ITopicProducer<RegisterNewServiceMessageType> serviceTopic) : ControllerBase
{
    [HttpPost]
    [HasPrivilege(GlobalPrivilage.Privilege.GlobalAdmin)]
    public async Task<ActionResult<CreateServiceTokenReturnModel>> GetTokenForService([FromBody] CreateServiceTokenModel req)
    {
        if (req is { ServiceName: not null, ServiceRoles: not null, ServicePrivilages: not null })
        {
            var result = new CreateServiceTokenReturnModel(req.ServiceName)
            {
                ServiceUsername = $"Service-{req.ServiceName}"
            };
            
            var userExist = await serviceManager.CheckIfServiceUserExist(req.ServiceName);
            if (!userExist)
            {
                var userRes = await serviceManager.CreateServiceUserResult(req.ServiceName, true);
                result.UserAllereadyExist = false;
                result.IsSuccess = userRes;
            }
            else
            {
                result.UserAllereadyExist = true;
            }

            var user = await userManager.FindByNameAsync($"Service-{req.ServiceName}");

            if (user == null)
            {
                return BadRequest();
            }
            
            result.PrivilageResults = await serviceManager.CreateServicesPrivilage(req.ServicePrivilages);
            result.RoleResults = await serviceManager.CreateServiceRoles(req.ServiceRoles);
            result.ServiceToken =
                await tokenRepo.CreateJwtToken(user, null, new List<Claim>() { AccountType.Service.Claim() });

            var topic = new RegisterNewServiceMessageType()
            {
                ServiceName = req.ServiceName,
                ServiceAccountUserName = user.UserName,
                ServicePrivilage = req.ServicePrivilages
            };

            _ = serviceTopic.Produce(topic);
            logger.LogInformation($"New service {req.ServiceName} with service account {user.UserName} " +
                                  $"and privileges {req.ServicePrivilages} register success.");
            
            
            return Ok(result);
        }
        else
        {
            return BadRequest();
        }
    }

    [HttpPost]
    [HasPrivilege(GlobalPrivilage.Privilege.GlobalAdmin)]
    public async Task<ActionResult<bool>> TestServiceToken()
    {
        var userId = HttpContext.User.Claims.FirstOrDefault(q => q.Type == ClaimTypes.NameIdentifier)?.Value;
        if (userId == null) return BadRequest();
        
        var user = await userManager.FindByIdAsync(userId);

        if (user == null) return Ok(false);
        
        var userClaim = await userManager.GetClaimsAsync(user);

        var serviceClaim = AccountType.Service.Claim();
        
        if(! userClaim.Any(q=> q.Type ==serviceClaim.Type && q.Value == serviceClaim.Value))
        {
            return Ok(false);
        }
        
        logger.LogInformation($"Regenerated token for service account: {user.UserName}");

        return Ok(true);
    }
}