using e_suite.API.Common.repository;
using e_suite.Database.Core;
using e_suite.Database.Core.Extensions;
using e_suite.Database.Core.Tables.Domain;
using eSuite.Core.Miscellaneous;
using Microsoft.EntityFrameworkCore;
using e_suite.Database.Audit;
using e_suite.Database.Core.Tables.UserManager;

namespace e_suite.Modules.RoleManager.Repository;

public class RoleManagerRepository : RepositoryBase, IRoleManagerRepository
{
    public RoleManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext)
    {
    }

    public IQueryable<Role> GetRolesList()
    {
        return DatabaseDbContext.Roles
            .Include(nameof(Role.Domain))
            .Where(x => !x.Deleted);
    }
    public Role? GetRoleById(IGeneralIdRef generalIdRef)
    {
        return DatabaseDbContext.Roles
            .Include(nameof(Domain)).AsEnumerable()
            .FindByGeneralIdRef(generalIdRef);
    }

    public async Task<Role?> GetRoleByIdAsync(IGeneralIdRef generalIdRef, CancellationToken cancellationToken)
    {
        return await DatabaseDbContext.Roles
            .Include(nameof(Domain))
            .FindByGeneralIdRefAsync(generalIdRef, cancellationToken);
    }

    public async Task<Role?> GetRoleByName(Domain domain, string name, CancellationToken cancellationToken)
    {
        return await DatabaseDbContext.Roles.Where(x => x.Name == name && x.Domain == domain).FirstOrDefaultAsync(cancellationToken);
    }

    public async Task EditRole(AuditUserDetails auditUserDetails, Role role, CancellationToken cancellationToken)
    {
        DatabaseDbContext.Roles.Update(role);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task AddRole(AuditUserDetails auditUserDetails, Role role, CancellationToken cancellationToken)
    {
        await DatabaseDbContext.Roles.AddAsync(role, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public IQueryable<UserRole> GetUserRoles()
    {
        return DatabaseDbContext.UserRoles
            .Include(nameof(Role))
            .Include(nameof(User))
            .Where(userRole => userRole.Deleted == false);
    }

    public async Task AddUserRole(AuditUserDetails auditUserDetails, Role existingRole, User existingUser,
        CancellationToken cancellationToken)
    {
        DatabaseDbContext.UserRoles.Add( new UserRole
        {
            Role = existingRole,
            User = existingUser
        });

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task DeleteUserRole(AuditUserDetails auditUserDetails, Role existingRole, User existingUser,
        CancellationToken cancellationToken)
    {
        var userRoles = GetUserRoles().Where(x => x.User == existingUser && x.Role == existingRole);
        DatabaseDbContext.UserRoles.RemoveRange(userRoles);

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public IQueryable<RoleAccess> GetAccessForRole()
    {
        return DatabaseDbContext.RoleAccess;
    }

    public async Task AddSecurityAccess(AuditUserDetails auditUserDetails, List<RoleAccess> rollAccessToAdd, CancellationToken cancellationToken)
    {
        await DatabaseDbContext.RoleAccess.AddRangeAsync(rollAccessToAdd, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task DeleteSecurityAccess(AuditUserDetails auditUserDetails, List<RoleAccess> rollAccessToDelete, CancellationToken cancellationToken)
    {
        foreach (var item in rollAccessToDelete)
        {
            DatabaseDbContext.RoleAccess.Remove(item);
        }

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public IQueryable<UserAccess> GetUserAccess()
    {
        return DatabaseDbContext.UserAccess;
    }
}