using Collaboration.Application.Interfaces; using Collaboration.Domain.Entities; using Collaboration.Domain.Enums; using Microsoft.EntityFrameworkCore; namespace Collaboration.Infrastructure.Repositories; public class CollabSessionRepository : ICollabSessionRepository { private readonly CollabDbContext _db; public CollabSessionRepository(CollabDbContext db) => _db = db; public Task GetByIdAsync(Guid id, CancellationToken ct = default) => _db.Sessions.FindAsync([id], ct).AsTask(); public Task GetByCodeAsync(string code, CancellationToken ct) => _db.Sessions.FirstOrDefaultAsync(s => s.SessionCode == code, ct); public Task GetWithParticipantsAsync(Guid id, CancellationToken ct) => _db.Sessions .Include(s => s.Participants.Where(p => p.IsActive)) .FirstOrDefaultAsync(s => s.SessionId == id, ct); public Task GetFullAsync(Guid id, CancellationToken ct) => _db.Sessions .Include(s => s.Participants) .Include(s => s.Invites) .FirstOrDefaultAsync(s => s.SessionId == id, ct); public Task> GetActiveByUserAsync(Guid userId, Guid orgId, CancellationToken ct) => _db.Sessions .Include(s => s.Participants.Where(p => p.IsActive)) .Where(s => s.OrgId == orgId && s.Status == SessionStatus.Active && s.Participants.Any(p => p.UserId == userId && p.IsActive)) .OrderByDescending(s => s.StartedAt) .ToListAsync(ct); public Task> GetScheduledByUserAsync(Guid userId, Guid orgId, CancellationToken ct) => _db.Sessions .Include(s => s.Participants) .Where(s => s.OrgId == orgId && s.Status == SessionStatus.Pending && s.ScheduledAt >= DateTime.UtcNow && (s.CreatedBy == userId || s.Participants.Any(p => p.UserId == userId))) .OrderBy(s => s.ScheduledAt) .ToListAsync(ct); public Task> GetAbandonedCandidatesAsync(int timeoutMinutes, CancellationToken ct) { var cutoff = DateTime.UtcNow.AddMinutes(-timeoutMinutes); return _db.Sessions .Where(s => s.Status == SessionStatus.Active && s.LastActivityAt < cutoff) .ToListAsync(ct); } public async Task AddAsync(CollabSession session, CancellationToken ct) { await _db.Sessions.AddAsync(session, ct); await _db.SaveChangesAsync(ct); } public Task SaveChangesAsync(CancellationToken ct) => _db.SaveChangesAsync(ct); } public class CollabParticipantRepository : ICollabParticipantRepository { private readonly CollabDbContext _db; public CollabParticipantRepository(CollabDbContext db) => _db = db; public Task GetByIdAsync(Guid id, CancellationToken ct) => _db.Participants.FindAsync([id], ct).AsTask(); public Task GetByConnectionIdAsync(string connectionId, CancellationToken ct) => _db.Participants.FirstOrDefaultAsync(p => p.SignalRConnectionId == connectionId && p.IsActive, ct); public Task GetActiveByUserAndSessionAsync(Guid userId, Guid sessionId, CancellationToken ct) => _db.Participants.FirstOrDefaultAsync( p => p.UserId == userId && p.SessionId == sessionId && p.IsActive, ct); public Task> GetActiveBySessionAsync(Guid sessionId, CancellationToken ct) => _db.Participants .Where(p => p.SessionId == sessionId && p.IsActive) .ToListAsync(ct); public Task GetCurrentControlHolderAsync(Guid sessionId, CancellationToken ct) => _db.Participants.FirstOrDefaultAsync( p => p.SessionId == sessionId && p.HasControl && p.IsActive, ct); public Task SaveChangesAsync(CancellationToken ct) => _db.SaveChangesAsync(ct); } public class CollabInviteRepository : ICollabInviteRepository { private readonly CollabDbContext _db; public CollabInviteRepository(CollabDbContext db) => _db = db; public Task GetByTokenAsync(string token, CancellationToken ct) => _db.Invites .Include(i => i.Session) .FirstOrDefaultAsync(i => i.InviteToken == token, ct); public Task GetByIdAsync(Guid id, CancellationToken ct) => _db.Invites.FindAsync([id], ct).AsTask(); public Task> GetPendingByUserAsync(Guid userId, CancellationToken ct) => _db.Invites .Include(i => i.Session) .Where(i => i.InvitedUserId == userId && i.Status == InviteStatus.Pending && i.ExpiresAt > DateTime.UtcNow) .OrderByDescending(i => i.CreatedAt) .ToListAsync(ct); public async Task AddAsync(CollabSessionInvite invite, CancellationToken ct) { await _db.Invites.AddAsync(invite, ct); await _db.SaveChangesAsync(ct); } public Task SaveChangesAsync(CancellationToken ct) => _db.SaveChangesAsync(ct); } public class CollabConfigRepository : ICollabConfigRepository { private readonly CollabDbContext _db; public CollabConfigRepository(CollabDbContext db) => _db = db; public Task GetByOrgAsync(Guid orgId, CancellationToken ct) => _db.Configs.FindAsync([orgId], ct).AsTask(); public async Task GetOrCreateDefaultAsync(Guid orgId, CancellationToken ct) { var config = await _db.Configs.FindAsync([orgId], ct); if (config is not null) return config; config = CollabConfig.CreateDefault(orgId); await _db.Configs.AddAsync(config, ct); await _db.SaveChangesAsync(ct); return config; } public async Task AddAsync(CollabConfig config, CancellationToken ct) { await _db.Configs.AddAsync(config, ct); await _db.SaveChangesAsync(ct); } public Task SaveChangesAsync(CancellationToken ct) => _db.SaveChangesAsync(ct); }