using System.Security.Cryptography;
using FastBlog.Core.Abstractions.Repositories.Users;
using FastBlog.Core.Models;
using FastBlog.Core.Models.Users;
using FastBlog.Core.Options;
using Microsoft.Extensions.Options;

namespace FastBlog.Core.Services;

public sealed class SessionService(
    ISessionRepository repository,
    UserService userService,
    IOptionsMonitor<SessionOptions> options)
{
    public async Task<Result<Session?, BusinessError>> Get(string token)
    {
        var session = await repository.Get(token);
        if (session is null)
            return null as Session;
        (bool slidingValid, bool absoluteValid) = options.CurrentValue.Validate(session);
       
        if(!slidingValid || !absoluteValid)
        {
            await repository.Deactivate(token);
            return new BusinessError("session-expired");
        }
        
        session.LastUsed = DateTime.UtcNow;
        
        if(session.LastUsed - session.CreatedAt > TimeSpan.FromSeconds(options.CurrentValue.TouchAfterSeconds))
            await repository.Touch(token);
        
        return session;
    }

    public async Task<Session?> Authenticate(string username, string password)
    {
        var user = await userService.GetByCredentials(username, password);
        
        if (user is null)
            return null;
        
        var session = new Session
        {
            UserId = user.Id,
            Token = RandomNumberGenerator.GetHexString(64, true),
            CreatedAt = DateTime.UtcNow,
            LastUsed = DateTime.UtcNow
        };
        
        return await repository.Set(session);
    }
    
    public Task<bool> Deactivate(string token) => repository.Deactivate(token);

    public Task<bool> RemoveAll(int userId) => repository.RemoveAll(userId);
}