using Microsoft.EntityFrameworkCore;
using Nexus.Api.Data;
using System.Text.Json;

namespace Nexus.Api.Repositories;

public sealed class ActivityRepository(NexusDbContext db, Nexus.Api.Services.ILiveUpdateService liveUpdates) : IActivityRepository
{
    public Task<List<ActivityEvent>> GetRecentAsync(int take, CancellationToken ct = default)
        => db.Activity.AsNoTracking().OrderByDescending(x => x.CreatedAt).Take(take).ToListAsync(ct);

    public Task<List<ActivityEvent>> GetRecentForTasksAsync(IEnumerable<Guid> taskIds, CancellationToken ct = default)
    {
        var ids = taskIds.Distinct().ToList();
        if (ids.Count == 0)
            return Task.FromResult(new List<ActivityEvent>());

        return db.Activity.AsNoTracking()
            .Where(x => x.TaskId.HasValue && ids.Contains(x.TaskId.Value))
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(ct);
    }

    public async Task<(List<ActivityEvent> Items, int TotalCount)> GetPagedAsync(
        string? type, string? sort, int page, int pageSize, CancellationToken ct = default)
    {
        var query = db.Activity.AsNoTracking();

        if (!string.IsNullOrWhiteSpace(type))
            query = query.Where(x => x.Type == type);

        query = (sort?.ToLowerInvariant()) switch
        {
            "oldest" => query.OrderBy(x => x.CreatedAt),
            _ => query.OrderByDescending(x => x.CreatedAt)
        };

        var totalCount = await query.CountAsync(ct);
        var items = await query.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync(ct);
        return (items, totalCount);
    }

    public async Task<List<ActivityEvent>> GetByAgentAsync(string agentId, int take, CancellationToken ct = default)
    {
        var candidateCount = Math.Max(take * 8, 100);
        var recent = await db.Activity.AsNoTracking()
            .OrderByDescending(x => x.CreatedAt)
            .Take(candidateCount)
            .ToListAsync(ct);

        return recent
            .Where(x => Nexus.Api.Services.AgentActivityText.MatchesAgent(x.Message, agentId))
            .Take(take)
            .ToList();
    }

    public async Task<ActivityEvent> AddAsync(ActivityEvent activity, CancellationToken ct = default)
    {
        var agentIds = Nexus.Api.Services.AgentActivityText.ExtractAgentIds(activity.Message);
        activity.Message = Nexus.Api.Services.AgentActivityText.RedactForDisplay(activity.Message);
        db.Activity.Add(activity);
        db.OutboxEvents.Add(new OutboxEvent
        {
            Type = "activity.created",
            AggregateType = "activity",
            AggregateId = activity.TaskId?.ToString() ?? Guid.NewGuid().ToString(),
            AggregateRevision = 0,
            PayloadJson = JsonSerializer.Serialize(new
            {
                type = activity.Type,
                taskId = activity.TaskId,
                agentIds
            })
        });
        await db.SaveChangesAsync(ct);
        liveUpdates.Publish("activity.created", new
        {
            activity.Id,
            activity.Type,
            activity.Message,
            activity.TaskId,
            activity.CreatedAt,
            agentIds
        }, "activity");
        return activity;
    }
}
