use eternaltwin_core::password::{PasswordService, PasswordServiceRef};

pub(crate) struct TestApi<TyPassword>
where
  TyPassword: PasswordServiceRef,
{
  pub(crate) password: TyPassword,
}

pub(crate) fn test_hash_and_verify<TyPassword>(api: TestApi<TyPassword>)
where
  TyPassword: PasswordServiceRef,
{
  let hash = api.password.password_service().hash("hunter2".into());
  assert!(api.password.password_service().verify(hash, "hunter2".into()));
}

pub(crate) fn test_reject_invalid_password<TyPassword>(api: TestApi<TyPassword>)
where
  TyPassword: PasswordServiceRef,
{
  let hash = api.password.password_service().hash("hunter2".into());
  assert!(!api.password.password_service().verify(hash, "foo".into()));
}

pub(crate) fn test_hashes_are_unique_even_for_same_passwords<TyPassword>(api: TestApi<TyPassword>)
where
  TyPassword: PasswordServiceRef,
{
  let first = api.password.password_service().hash("hunter2".into());
  let second = api.password.password_service().hash("hunter2".into());
  assert_ne!(first, second);
  assert!(api.password.password_service().verify(first, "hunter2".into()));
  assert!(api.password.password_service().verify(second, "hunter2".into()));
}

pub(crate) fn test_supports_having_different_passwords<TyPassword>(api: TestApi<TyPassword>)
where
  TyPassword: PasswordServiceRef,
{
  let hunter_hash = api.password.password_service().hash("hunter2".into());
  let foo_hash = api.password.password_service().hash("foo".into());
  assert!(api
    .password
    .password_service()
    .verify(hunter_hash.clone(), "hunter2".into()));
  assert!(api.password.password_service().verify(foo_hash.clone(), "foo".into()));
  assert!(!api
    .password
    .password_service()
    .verify(hunter_hash.clone(), "foo".into()));
  assert!(!api
    .password
    .password_service()
    .verify(foo_hash.clone(), "hunter2".into()));
  assert!(api.password.password_service().verify(foo_hash, "foo".into()));
  assert!(api.password.password_service().verify(hunter_hash, "hunter2".into()));
}
