using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using FastEndpoints;
using FastEndpoints.Security;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using TrackQrApi.Data;
using TrackQrApi.Features.Auth.Common;
using TrackQrApi.Features.Auth.Settings;

namespace TrackQrApi.Features.Auth.Endpoints;

public class LoginRequest
{
    public string Email { get; set; } = string.Empty;
    public string Password { get; set; } = string.Empty;
}

public class LoginValidator : Validator<LoginRequest>
{
    public LoginValidator()
    {
        RuleFor(x => x.Email)
            .NotEmpty().WithMessage("Email is required")
            .EmailAddress().WithMessage("Invalid email format");

        RuleFor(x => x.Password)
            .NotEmpty().WithMessage("Password is required");
    }
}

public class LoginEndpoint(AppDbContext db, IOptions<JwtSettings> jwtSettings)
    : Endpoint<LoginRequest, AuthResponse>
{
    private readonly JwtSettings _jwtSettings = jwtSettings.Value;

    public override void Configure()
    {
        Post("/auth/login");
        AllowAnonymous();
        Options(x => x.RequireRateLimiting("auth"));
    }

    public override async Task HandleAsync(LoginRequest req, CancellationToken ct)
    {
        var normalizedEmail = req.Email.ToLowerInvariant();
        var user = await db.Users.FirstOrDefaultAsync(u => u.Email == normalizedEmail, ct);

        if (user == null || !BCrypt.Net.BCrypt.Verify(req.Password, user.PasswordHash))
        {
            await HttpContext.Response.SendAsync(new MessageResponse("Invalid email or password"), 401,
                cancellation: ct);
            return;
        }

        Logger.LogInformation("User logged in: {Email}", normalizedEmail);

        var expiresAt = DateTime.UtcNow.AddMinutes(_jwtSettings.ExpirationMinutes);

        var jwtToken = JwtBearer.CreateToken(o =>
        {
            o.SigningKey = _jwtSettings.Secret;
            o.Issuer = _jwtSettings.Issuer;
            o.Audience = _jwtSettings.Audience;
            o.ExpireAt = expiresAt;
            //o.User.Roles.Add("Manager", "Auditor");
            o.User.Claims.Add(
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
                new Claim(JwtRegisteredClaimNames.Email, user.Email),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            );
        });

        var response = new AuthResponse(
            jwtToken,
            expiresAt,
            new UserInfo(user.Id, user.Email, user.VerifiedAt.HasValue)
        );

        await HttpContext.Response.SendAsync(response, cancellation: ct);
    }
}