using System.Security.Cryptography;
using System.Text;

namespace PasswordMigrationUtil
{
    public class PasswordHasherService
    {
        private const int SaltSize = 16; // 128 bit
        private const int HashSize = 32; // 256 bit
        private const int Iterations = 10000; // Número de iteraciones (ajustable)

        // Genera un hash y una salt para una contraseña dada
        public (string hash, string salt) HashPassword(string password)
        {
            // Generar una salt aleatoria
            byte[] saltBytes = RandomNumberGenerator.GetBytes(SaltSize);

            // Crear el hash usando PBKDF2
            var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, Iterations, HashAlgorithmName.SHA256);
            byte[] hashBytes = pbkdf2.GetBytes(HashSize);

            // Convertir bytes a strings Base64 para almacenamiento
            string saltString = Convert.ToBase64String(saltBytes);
            string hashString = Convert.ToBase64String(hashBytes);

            return (hashString, saltString);
        }

        // Verifica si una contraseña coincide con un hash y salt almacenados
        public bool VerifyPassword(string password, string storedHash, string storedSalt)
        {
            try
            {
                // Convertir strings Base64 de vuelta a bytes
                byte[] saltBytes = Convert.FromBase64String(storedSalt);
                byte[] storedHashBytes = Convert.FromBase64String(storedHash);

                // Crear el hash de la contraseña ingresada usando la misma salt e iteraciones
                var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, Iterations, HashAlgorithmName.SHA256);
                byte[] testHashBytes = pbkdf2.GetBytes(HashSize);

                // Comparar los hashes de forma segura (evita timing attacks)
                return CryptographicOperations.FixedTimeEquals(storedHashBytes, testHashBytes);
            }
            catch (FormatException)
            {
                // Manejar el caso donde las strings almacenadas no son Base64 válidas
                return false;
            }
            catch (Exception)
            {
                // Loggear la excepción si es necesario
                return false;
            }
        }
    }
}