using Microsoft.EntityFrameworkCore;
using OmsorgCore.Application.Abstractions;
using OmsorgCore.Domain.Entities;
using OmsorgCore.Infrastructure.Persistence;

namespace OmsorgCore.Infrastructure.Repositories;

public class UserRepository : IUserRepository
{
    private readonly OmsorgCoreDbContext _db;

    public UserRepository(OmsorgCoreDbContext db)
    {
        _db = db;
    }

    public Task<User?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default)
        => _db.Users
            .Include(u => u.Role)
            .Include(u => u.Employee)
            .FirstOrDefaultAsync(u => u.Username == username, cancellationToken);

    public Task<User?> GetByIdWithPermissionsAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.Users
            .Include(u => u.Role)
                .ThenInclude(r => r.RolePermissions)
            .Include(u => u.PermissionOverrides)
            .Include(u => u.Employee)
            .FirstOrDefaultAsync(u => u.Id == id, cancellationToken);

    public Task<User?> GetByIdWithPermissionsNoTrackingAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.Users
            .AsNoTracking()
            .Include(u => u.Role)
                .ThenInclude(r => r.RolePermissions)
            .Include(u => u.PermissionOverrides)
            .Include(u => u.Employee)
            .FirstOrDefaultAsync(u => u.Id == id, cancellationToken);

    public Task<User?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.Users.FirstOrDefaultAsync(u => u.Id == id, cancellationToken);

    public Task<User?> GetByIdWithEmployeeAsync(Guid id, CancellationToken cancellationToken = default)
        => _db.Users
            .Include(u => u.Role)
            .Include(u => u.Employee)
            .FirstOrDefaultAsync(u => u.Id == id, cancellationToken);

    public async Task<IReadOnlyList<User>> GetAllAsync(CancellationToken cancellationToken = default)
        => await _db.Users.Include(u => u.Role).ToListAsync(cancellationToken);

    public async Task<IReadOnlyList<Guid>> GetUserIdsByRoleAsync(Guid roleId, CancellationToken cancellationToken = default)
        => await _db.Users.Where(u => u.RoleId == roleId).Select(u => u.Id).ToListAsync(cancellationToken);

    public Task<User?> GetByEmployeeIdAsync(Guid employeeId, CancellationToken cancellationToken = default)
        => _db.Users.FirstOrDefaultAsync(u => u.EmployeeId == employeeId, cancellationToken);

    public Task<bool> ExistsByUsernameAsync(string username, CancellationToken cancellationToken = default)
        => _db.Users.AnyAsync(u => u.Username == username, cancellationToken);

    public async Task AddAsync(User user, CancellationToken cancellationToken = default)
        => await _db.Users.AddAsync(user, cancellationToken);

    public async Task AddPermissionOverrideAsync(UserPermissionOverride @override, CancellationToken cancellationToken = default)
        => await _db.UserPermissionOverrides.AddAsync(@override, cancellationToken);

    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
        => _db.SaveChangesAsync(cancellationToken);
}
