using ColaFlow.Modules.Mcp.Domain.Entities;
using ColaFlow.Modules.Mcp.Domain.Repositories;
using ColaFlow.Modules.Mcp.Domain.ValueObjects;
using Microsoft.EntityFrameworkCore;

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

/// <summary>
/// Repository implementation for PendingChange aggregate
/// </summary>
public sealed class PendingChangeRepository(McpDbContext context) : IPendingChangeRepository
{
    private readonly McpDbContext _context = context ?? throw new ArgumentNullException(nameof(context));

    public async Task<PendingChange?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.PendingChanges
            .FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
    }

    public async Task<IReadOnlyList<PendingChange>> GetByTenantAsync(
        Guid tenantId,
        CancellationToken cancellationToken = default)
    {
        return await _context.PendingChanges
            .Where(p => p.TenantId == tenantId)
            .OrderByDescending(p => p.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<PendingChange>> GetByStatusAsync(
        Guid tenantId,
        PendingChangeStatus status,
        CancellationToken cancellationToken = default)
    {
        return await _context.PendingChanges
            .Where(p => p.TenantId == tenantId && p.Status == status)
            .OrderByDescending(p => p.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<PendingChange>> GetExpiredAsync(
        CancellationToken cancellationToken = default)
    {
        var now = DateTime.UtcNow;
        return await _context.PendingChanges
            .Where(p => p.Status == PendingChangeStatus.PendingApproval && p.ExpiresAt < now)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<PendingChange>> GetByApiKeyAsync(
        Guid apiKeyId,
        CancellationToken cancellationToken = default)
    {
        return await _context.PendingChanges
            .Where(p => p.ApiKeyId == apiKeyId)
            .OrderByDescending(p => p.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<PendingChange>> GetByEntityAsync(
        Guid tenantId,
        string entityType,
        Guid entityId,
        CancellationToken cancellationToken = default)
    {
        return await _context.PendingChanges
            .Where(p => p.TenantId == tenantId
                && p.Diff.EntityType == entityType
                && p.Diff.EntityId == entityId)
            .OrderByDescending(p => p.CreatedAt)
            .ToListAsync(cancellationToken);
    }

    public async Task<bool> HasPendingChangesForEntityAsync(
        Guid tenantId,
        string entityType,
        Guid entityId,
        CancellationToken cancellationToken = default)
    {
        return await _context.PendingChanges
            .AnyAsync(p => p.TenantId == tenantId
                && p.Diff.EntityType == entityType
                && p.Diff.EntityId == entityId
                && p.Status == PendingChangeStatus.PendingApproval,
                cancellationToken);
    }

    public async Task AddAsync(PendingChange pendingChange, CancellationToken cancellationToken = default)
    {
        await _context.PendingChanges.AddAsync(pendingChange, cancellationToken);
    }

    public Task UpdateAsync(PendingChange pendingChange, CancellationToken cancellationToken = default)
    {
        _context.PendingChanges.Update(pendingChange);
        return Task.CompletedTask;
    }

    public Task DeleteAsync(PendingChange pendingChange, CancellationToken cancellationToken = default)
    {
        _context.PendingChanges.Remove(pendingChange);
        return Task.CompletedTask;
    }

    public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        return await _context.SaveChangesAsync(cancellationToken);
    }
}
