using MediatR;
using Microsoft.AspNetCore.Http;
using Modules.User.Application.Gateways;
using Modules.User.Application.Models;

namespace Modules.User.Application.Commands;

public class RefreshTokensCommand : IRequest<AuthenticationResult?>
{
    public string? Ip { get; set; }
    public HttpResponse Response { get; set; } = default!;
    public string? CookiePath { get; set; }
}

public class RefreshTokensCommandHandler(UserContext userContext, IAccountGateway accountGateway,
    IUserGateway userGateway, TokenGenerator tokenGenerator) : IRequestHandler<RefreshTokensCommand, AuthenticationResult?>
{
    public async Task<AuthenticationResult?> Handle(RefreshTokensCommand request, CancellationToken cancellationToken)
    {
        var refreshToken = userContext.GetRefreshToken();
        if (refreshToken == null)
        {
            return null;
        }
        else
        {
            var session = await accountGateway.TryGetSession(refreshToken);
            if (session == null) return null;
            var user = await userGateway.Get(session.AccountId);
            if (user == null) return null;

            var userAgent = userContext.GetUserAgent();
            var location = await userContext.GetLocation(request.Ip);

            var jwtSettings = userContext.GetJwtSettings();
            var newRefreshToken = user.Account.UpdateRefreshToken(session.Id, tokenGenerator, jwtSettings.RefreshTokenExpireTime, userAgent, location?.Country, location?.Region);
            await accountGateway.UpdateSessions(user.Account.Id, user.Account.Sessions.Select(q => new Session
            {
                Id = q.Id,
                RefreshToken = q.RefreshToken,
                ClientInfo = new ClientInfo
                {
                    UserAgent = q.ClientInfo.UserAgent,
                    Location = new Location
                    {
                        Country = q.ClientInfo.Country,
                        Region = q.ClientInfo.Region,
                    }
                },
                AccountId = q.AccountId,
                ExpiredDate = q.ExpiredDate,
            }));
            if (newRefreshToken == null) return null;
            var accessToken = tokenGenerator.GenerateAccessToken(user, user.Account.Sessions.First(q => q.Id == session.Id)!, jwtSettings);
            TokenGenerator.SetRefreshTokenInCookie(request.Response, request.CookiePath, newRefreshToken, user.Account.Sessions.First(q => q.Id == session.Id).ExpiredDate);
            return new() { AccessToken = accessToken, SessionExpireDate = session.ExpiredDate, };
        }
    }
}