using Microsoft.AspNetCore.Identity;

namespace ErsatzTV.Application.Auth;

/// <summary>
///     <see cref="ILocalPasswordHasher" /> backed by ASP.NET Core Identity's <see cref="PasswordHasher{TUser}" />
///     (PBKDF2-HMAC-SHA512, per-hash random salt, format-versioned so a future work-factor bump is a
///     transparent rehash-on-verify). Stateless and thread-safe → registered as a singleton.
/// </summary>
public sealed class LocalPasswordHasher : ILocalPasswordHasher
{
    // The generic user parameter is unused by the hasher (it takes no per-user data), so a shared sentinel
    // is fine.
    private static readonly object Sentinel = new();

    private readonly PasswordHasher<object> _hasher = new();
    private readonly Lazy<string> _dummyHash;

    public LocalPasswordHasher() =>
        _dummyHash = new Lazy<string>(() => _hasher.HashPassword(Sentinel, "not-a-real-password"));

    public string DummyHash => _dummyHash.Value;

    public string Hash(string password) => _hasher.HashPassword(Sentinel, password);

    public LocalPasswordVerification Verify(string hash, string password) =>
        _hasher.VerifyHashedPassword(Sentinel, hash, password) switch
        {
            PasswordVerificationResult.Success => LocalPasswordVerification.Success,
            PasswordVerificationResult.SuccessRehashNeeded => LocalPasswordVerification.SuccessRehashNeeded,
            _ => LocalPasswordVerification.Failed
        };
}
