using System.Security.Cryptography;

namespace Meezi.Core.Utilities;

/// <summary>
/// PBKDF2/SHA-256 password hashing with no external dependencies.
/// Format stored: "{iterations}.{salt_b64}.{hash_b64}"
/// </summary>
public static class PasswordHasher
{
    private const int SaltSize   = 16;        // 128-bit salt
    private const int HashSize   = 32;        // 256-bit hash
    private const int Iterations = 100_000;   // NIST-recommended minimum
    private static readonly HashAlgorithmName Algo = HashAlgorithmName.SHA256;

    public static string Hash(string password)
    {
        var salt = RandomNumberGenerator.GetBytes(SaltSize);
        var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, Algo, HashSize);
        return $"{Iterations}.{Convert.ToBase64String(salt)}.{Convert.ToBase64String(hash)}";
    }

    public static bool Verify(string password, string storedHash)
    {
        var parts = storedHash.Split('.');
        if (parts.Length != 3) return false;
        if (!int.TryParse(parts[0], out var iterations)) return false;

        byte[] salt, expectedHash;
        try
        {
            salt         = Convert.FromBase64String(parts[1]);
            expectedHash = Convert.FromBase64String(parts[2]);
        }
        catch (FormatException) { return false; }

        var actual = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, Algo, expectedHash.Length);
        return CryptographicOperations.FixedTimeEquals(actual, expectedHash);
    }
}
