using ColaFlow.Modules.Identity.Domain.Aggregates.Users;
using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
using ColaFlow.Modules.Identity.Domain.Repositories;
using Microsoft.EntityFrameworkCore;

namespace ColaFlow.Modules.Identity.Infrastructure.Persistence.Repositories;

public class UserRepository(IdentityDbContext context) : IUserRepository
{
    public async Task<User?> GetByIdAsync(UserId userId, CancellationToken cancellationToken = default)
    {
        // Global Query Filter automatically applies
        return await context.Users
            .FirstOrDefaultAsync(u => u.Id == userId, cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<User?> GetByIdAsync(Guid userId, CancellationToken cancellationToken = default)
    {
        var userIdVO = UserId.Create(userId);
        return await context.Users
            .FirstOrDefaultAsync(u => u.Id == userIdVO, cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<IReadOnlyList<User>> GetByIdsAsync(
        IEnumerable<Guid> userIds,
        CancellationToken cancellationToken = default)
    {
        var userIdsList = userIds.ToList();

        // Optimized: Single query instead of N+1 queries
        return await context.Users
            .Where(u => userIdsList.Contains(u.Id))
            .ToListAsync(cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<User?> GetByEmailAsync(TenantId tenantId, Email email, CancellationToken cancellationToken = default)
    {
        return await context.Users
            .FirstOrDefaultAsync(u => u.TenantId == tenantId && u.Email == email, cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<User?> GetByExternalIdAsync(
        TenantId tenantId,
        AuthenticationProvider provider,
        string externalUserId,
        CancellationToken cancellationToken = default)
    {
        return await context.Users
            .FirstOrDefaultAsync(
                u => u.TenantId == tenantId &&
                     u.AuthProvider == provider &&
                     u.ExternalUserId == externalUserId,
                cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<bool> ExistsByEmailAsync(TenantId tenantId, Email email, CancellationToken cancellationToken = default)
    {
        return await context.Users
            .AnyAsync(u => u.TenantId == tenantId && u.Email == email, cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<IReadOnlyList<User>> GetAllByTenantAsync(TenantId tenantId, CancellationToken cancellationToken = default)
    {
        return await context.Users
            .Where(u => u.TenantId == tenantId)
            .ToListAsync(cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task<int> GetActiveUsersCountAsync(TenantId tenantId, CancellationToken cancellationToken = default)
    {
        return await context.Users
            .CountAsync(u => u.TenantId == tenantId && u.Status == UserStatus.Active, cancellationToken)
            .ConfigureAwait(false);
    }

    public async Task AddAsync(User user, CancellationToken cancellationToken = default)
    {
        await context.Users.AddAsync(user, cancellationToken).ConfigureAwait(false);
        await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
    }

    public async Task UpdateAsync(User user, CancellationToken cancellationToken = default)
    {
        context.Users.Update(user);
        await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
    }

    public async Task DeleteAsync(User user, CancellationToken cancellationToken = default)
    {
        context.Users.Remove(user);
        await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
    }
}
