using BCrypt.Net ;
using Biskilog_Accounting.Shared.ClientContractModels ;
using Biskilog_Accounting.Shared.Enums ;
using Biskilog_Accounting.Shared.Interfaces ;
using Microsoft.EntityFrameworkCore ;
namespace Biskilog_Accounting.Server.Services
{
public class AuthenticationService : IAuthService
{
private readonly BiskilogContext m_context ;
private readonly ITokenService m_tokenService ;
public AuthenticationService ( BiskilogContext a_context , ITokenService a_tokenService )
{
m_context = a_context ;
m_tokenService = a_tokenService ;
}
/// <summary>
/// Returns the status of a user account
/// </summary>
/// <returns>AuthEnums</returns>
public AuthEnums AccountStatus ( int? a_id , string? a_username )
{
if ( m_context . Userauths . Any ( i = > i . UserId = = a_id | | i . Username = = a_username ) )
{
return AuthEnums . Found ;
}
else
{
return AuthEnums . NotFound ;
}
}
/// <summary>
/// Autenticates a user and returns a tokenized string
/// </summary>
/// <param name="a_username"></param>
/// <param name="a_password"></param>
/// <returns>strings</returns>
public async Task < string > AuthenticateClient ( string a_username , string a_password )
{
var user = await GetUserAsync ( a_username , a_password ) ;
if ( user = = null )
{
return null ;
}
user . LastLogin = DateTime . Now ;
m_context . Userauths . Update ( user ) ;
m_context . SaveChanges ( ) ;
Databasemap databasemap = GetClientDB ( user . ClientId ) ;
List < int > businessIds = GetSiteaccesspermission ( user . ClientId , user . UserId ) . Select ( t = > t . BusinessId ) . ToList ( ) ;
Contract ? contract = GetContract ( user . ClientId , businessIds ) ;
List < string > businesses = GetClientbusiness ( user . ClientId , user . UserId ) . Select ( t = > t . BusinessExternalId ) . ToList ( ) ;
if ( contract = = null )
return AuthEnums . Invalid . ToString ( ) ;
return m_tokenService . GenerateToken ( user , contract , databasemap , businesses , false ) ;
}
/// <summary>
/// Creates a new user account
/// </summary>
/// returns AuthEnums.successful if the account was created successfully
public AuthEnums CreateUser ( Userauth a_user )
{
throw new NotImplementedException ( ) ;
//if (AccountStatus(null, a_user.Username) == AuthEnums.Found)
// return AuthEnums.Registered;
//a_user.Role = m_context.UserRoles.First(i => i.RoleId== a_user.RoleId);
//a_user.Password = BCrypt.Net.BCrypt.HashPassword(a_user.Password);
//m_context.Users.Add(a_user);
//var result = m_context.SaveChangesAsync();
//result.Wait();
//if(result.Result > 0)
//{
// return AuthEnums.Successful;
//}
//return AuthEnums.Error;
}
/// <summary>
/// Deletes a user account
/// </summary>
/// <exception cref="NotImplementedException"></exception>
public void DeleteUser ( int a_id )
{
throw new NotImplementedException ( ) ;
}
public List < Clientbusiness > GetClientbusiness ( int a_clientId , int userId )
{
return ( from b in m_context . Clientbusinesses
join p in m_context . Siteaccesspermissions on new { b . ClientId , b . BusinessId } equals new { p . ClientId , p . BusinessId }
where p . UserId = = userId & & p . ClientId = = a_clientId
select b ) . ToList ( ) ;
}
public Databasemap GetClientDB ( int a_clientId )
{
return m_context . Databasemaps . First ( t = > t . ClientId = = a_clientId ) ;
}
public Contract ? GetContract ( int a_clientId , List < int > a_businessId )
{
return m_context . Contracts . FirstOrDefault ( c = > c . ClientId = = a_clientId & & a_businessId . Contains ( c . BusinessId ! . Value ) & & c . EndDate > = DateTime . Now ) ;
}
public List < Siteaccesspermission > GetSiteaccesspermission ( int a_clientId , int a_userId )
{
return m_context . Siteaccesspermissions . Where ( t = > t . ClientId = = a_clientId & & t . UserId = = a_userId ) . ToList ( ) ;
}
private async Task < Userauth ? > GetUserAsync ( string username , string password )
{
//Todo have complete implementation after means of creating user is done
try
{
string? pa = await m_context . Userauths . Where ( u = > u . Username = = username | | u . Email = = username ) . Select ( u = > u . Passsword ) . FirstOrDefaultAsync ( ) ;
if ( String . IsNullOrEmpty ( pa ) )
{
return null ;
}
bool verified = BCrypt . Net . BCrypt . Verify ( password , pa ) ;
if ( verified )
{
return await m_context . Userauths . FirstAsync ( u = > u . Username = = username | | u . Email = = username ) ;
}
else
{
return null ;
}
}
catch ( Exception ex )
{
//possible is user not found
return null ;
}
}
}
}