using System.Text;
using System.Text.Unicode;
using Femto.Common.Domain;
using Femto.Modules.Auth.Contracts;
using Femto.Modules.Auth.Models.Events;
using Geralt;

namespace Femto.Modules.Auth.Models;

internal class UserIdentity : Entity
{
    public Guid Id { get; private set; }

    public string Username { get; private set; }

    public Password? Password { get; private set; }

    public ICollection<UserSession> Sessions { get; private set; } = [];

    public ICollection<UserRole> Roles { get; private set; } = [];

    private UserIdentity() { }

    public UserIdentity(string username)
    {
        this.Id = Guid.CreateVersion7();
        this.Username = username;

        this.Roles = [new UserRole(Role.User)];

        this.AddDomainEvent(new UserWasCreatedEvent(this));
    }

    public UserIdentity WithPassword(string password)
    {
        this.SetPassword(password);
        return this;
    }

    public void SetPassword(string password)
    {
        this.Password = new Password(password);
    }

    public bool HasPassword(string requestPassword)
    {
        if (this.Password is null)
        {
            return false;
        }

        return this.Password.Check(requestPassword);
    }

    public UserSession PossiblyRefreshSession(string sessionId)
    {
        var session = this.Sessions.Single(s => s.Id == sessionId);

        if (session.ExpiresSoon)
            return this.StartNewSession();

        return session;
    }

    public UserSession StartNewSession()
    {
        var session = UserSession.Create();

        this.Sessions.Add(session);

        return session;
    }
}

public class SetPasswordError(string message, Exception inner) : DomainError(message, inner);
