using adas_core.Application.Exceptions;
using adas_core.Authentication.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Exceptions;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Utils;
using Microsoft.AspNetCore.Http;
using MongoDB.Bson;
using Serilog;

namespace adas_core.LocalLogin;

public class LocalLoginServiceImpl(
    ILocalLoginRepository localLoginRepository,
    IAuthorityService authorityService)
    : ILoginService
{
    public bool AllowPassword => true;
    public UserEnum.LoginMethod Method => UserEnum.LoginMethod.Local;


    public async Task<User> Login(string username, string password)
    {
        var userFound = await localLoginRepository.GetByUsername(username) ??
                        throw new UnauthorizedException(HttpEnum.ErrorMessage.UnauthorizedInvalidCredentials);

        if (!CryptoAdas.VerifyPassword(password, userFound.Password))
            throw new UnauthorizedException(HttpEnum.ErrorMessage.UnauthorizedInvalidCredentials);

        userFound.Authorization = await authorityService.GetUserAuthorities(userFound.Id);
        return userFound;
    }

    public Task<User> Login(HttpContext context)
    {
        throw new LoginServicesException("Not implemented");
    }

    public async Task<User> Authenticate(string username, string password)
    {
        try
        {
            var userFound = await localLoginRepository.GetByUsername(username);

            if (userFound != null && CryptoAdas.VerifyPassword(password, userFound.Password)) return userFound;

            return new User();
        }
        catch (Exception e)
        {
            Log.Error("Error Authenticate with username-password: {username}: Exception: {exception}", username, e.Message);
            throw;
        }
    }

    public async Task<User?> GetById(ObjectId id)
    {
        return await localLoginRepository.GetById(id);
    }

    public async Task<User?> GetByEmail(string email)
    {
        return await localLoginRepository.GetByEmail(email);
    }

    public async Task<User?> GetByUsername(string username)
    {
        return await localLoginRepository.GetByUsername(username);
    }

    public async Task<List<User>> GetAllUsers()
    {
        return await localLoginRepository.GetAll();
    }
}