using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Predictalytics.Domain.Entities;
using Predictalytics.Domain.Enums;
using Predictalytics.Domain.Interfaces;

namespace Predictalytics.Api.Endpoints;

public static class JobEndpoints
{
    public static void MapJobEndpoints(this IEndpointRouteBuilder routes)
    {
        var group = routes.MapGroup("/api/jobs").WithTags("Jobs");

        group.MapGet("/", async (IJobRepository repo, int skip = 0, int take = 50, CancellationToken ct = default) =>
        {
            var jobs = await repo.GetAllAsync(skip, take, ct);
            return Results.Ok(jobs.Select(j => new
            {
                j.Id,
                JobType = j.JobType.ToString(),
                Status = j.Status.ToString(),
                j.TraderId,
                TraderName = j.Trader?.DisplayName ?? j.Trader?.PlatformUserId,
                j.CreatedAt,
                j.StartedAt,
                j.CompletedAt,
                j.ErrorMessage
            }));
        });

        group.MapPost("/sync/{traderId:int}", async (int traderId, IJobRepository repo, CancellationToken ct) =>
        {
            var job = new BackgroundJob
            {
                JobType = JobType.HistorySync,
                Status = JobStatus.Pending,
                TraderId = traderId
            };
            await repo.AddAsync(job, ct);
            return Results.Ok(job.Id);
        });

        group.MapPost("/analyze/{traderId:int}", async (int traderId, IJobRepository repo, CancellationToken ct) =>
        {
            var job = new BackgroundJob
            {
                JobType = JobType.TraderAnalysis,
                Status = JobStatus.Pending,
                TraderId = traderId
            };
            await repo.AddAsync(job, ct);
            return Results.Ok(job.Id);
        });

        group.MapPost("/deep-resync/{traderId:int}", async (int traderId, IJobRepository repo, CancellationToken ct) =>
        {
            var job = new BackgroundJob
            {
                JobType = JobType.DeepResync,
                Status = JobStatus.Pending,
                TraderId = traderId
            };
            await repo.AddAsync(job, ct);
            return Results.Ok(job.Id);
        });

        group.MapPost("/deep-resync-pruned", async (Predictalytics.Infrastructure.Data.AppDbContext db, IJobRepository repo, CancellationToken ct) =>
        {
            var traderIds = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(
                db.TraderPositions.Where(tp => tp.IsHistoryPruned).Select(tp => tp.TraderId).Distinct(), ct);

            int count = 0;
            foreach (var tid in traderIds)
            {
                var job = new BackgroundJob
                {
                    JobType = JobType.DeepResync,
                    Status = JobStatus.Pending,
                    TraderId = tid
                };
                await repo.AddAsync(job, ct);
                count++;
            }
            return Results.Ok(new { Count = count });
        });

        group.MapPost("/analyze-backlog", async (int? take, IJobRepository repo, Predictalytics.Infrastructure.Data.AppDbContext db, CancellationToken ct) =>
        {
            int batchSize = take ?? 50;
            
            var traderIds = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(
                db.Traders
                    .Where(t => t.LastAnalyzedAt == null || (t.LastTradesUpdatedAt != null && t.LastTradesUpdatedAt > t.LastAnalyzedAt))
                    .OrderBy(t => t.LastAnalyzedAt == null ? 0 : 1)
                    .ThenByDescending(t => t.TotalTrades)
                    .Select(t => t.Id)
                    .Take(batchSize),
                ct);
            var pendingTraderIds = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(
                db.BackgroundJobs
                    .Where(j => j.JobType == JobType.TraderAnalysis && j.Status == JobStatus.Pending && j.TraderId != null)
                    .Select(j => j.TraderId!.Value),
                ct);

            var pendingSet = pendingTraderIds.ToHashSet();

            int queued = 0;
            foreach (var tId in traderIds)
            {
                if (pendingSet.Contains(tId)) continue;
                
                var job = new BackgroundJob
                {
                    JobType = JobType.TraderAnalysis,
                    Status = JobStatus.Pending,
                    TraderId = tId
                };
                await repo.AddAsync(job, ct);
                queued++;
            }
            return Results.Ok(new { Queued = queued });
        });
    }
}
