using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services.Interfaces;
using adas_core.Authentication.Interfaces;
using adas_core.Domain.Models.MongoModels;
using Microsoft.AspNetCore.Http;
using MongoDB.Bson;
using Serilog;

namespace adas_core.Authentication;

public class AuthorityService(
    IAuthorityRepository authorityRepository,
    IHttpContextAccessor httpContextAccessor,
    ILocalAuditService auditService)
    : IAuthorityService
{
    public void CreateNew(string roleName, ObjectId userId)
    {
        authorityRepository.CreateNewAuthority(roleName, userId);
    }

    public async Task InsertOne(Authorization authorization)
    {
        await authorityRepository.InsertOneAsync(authorization);
        await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, authorization);
    }

    public async Task updateOne(Authorization authorization)
    {
        var oldAuth = await authorityRepository.GetById(authorization.Id);
        await authorityRepository.UpdateOneAsync(authorization.Id, authorization);
        await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldAuth, authorization);
    }

    /// <summary>
    ///     Retrieves the authorities of the specified user.
    /// </summary>
    /// <param name="userId"></param>
    /// <returns>A list of the user's authorities.</returns>
    public Task<List<Authorization>> GetUserAuthorities(ObjectId userId)
    {
        return authorityRepository.GetUserAuthorities(userId);
    }

    public Task<List<Authorization>> GetAllAuthorities()
    {
        return authorityRepository.GetAllAuthorities();
    }

    public async Task<bool> DeleteAuthoritiesForUser(ObjectId id)
    {
        try
        {
            var list = await authorityRepository.GetUserAuthorities(id);
            var result = await authorityRepository.DeleteAllAuthoritiesByUser(id);
            if (!result) return result;

            foreach (var auth in list)
                await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, auth, null);
            return result;
        }
        catch (Exception e)
        {
            Log.Error("Exception deleting authorities for user {id}. Exception: {e}", id, e.Message);
            return false;
        }
    }

    public async Task<Authorization?> CreateNewUserAuthority(Authorization authorization)
    {
        await authorityRepository.InsertOneAsync(authorization);
        await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, authorization);
        return authorization;
    }

    public async Task<bool> DeleteUserAuthority(ObjectId userAuthorityIdParsed)
    {
        try
        {
            var result = await authorityRepository.DeleteAsync(userAuthorityIdParsed);
            if (result != null)
                await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, result, null);
            return result != null;
        }
        catch (Exception e)
        {
            Log.Error("Exception deleting user authority {userAuthorityIdParsed}. Exception: {e}",
                userAuthorityIdParsed, e.Message);
            return false;
        }
    }

    public async Task<Authorization?> EditUserAuthority(Authorization authorization)
    {
        try
        {
            var oldAuth = await authorityRepository.GetById(authorization.Id);
            await authorityRepository.UpdateOneAsync(authorization.Id, authorization);
            await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldAuth, authorization);
            return authorization;
        }
        catch (Exception e)
        {
            Log.Error("Exception editing user authority {authorization}. Exception: {e}", authorization, e.Message);
            return null;
        }
    }
}