using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Predictalytics.Domain.Entities;
using Predictalytics.Domain.Enums;
using Predictalytics.Domain.Interfaces;

namespace Predictalytics.Infrastructure.Data.Repositories;

public class JobRepository : IJobRepository
{
    private readonly AppDbContext _db;

    public JobRepository(AppDbContext db)
    {
        _db = db;
    }

    public async Task<BackgroundJob?> GetByIdAsync(int id, CancellationToken ct = default)
    {
        return await _db.BackgroundJobs.Include(j => j.Trader).FirstOrDefaultAsync(j => j.Id == id, ct);
    }

    public async Task<IReadOnlyList<BackgroundJob>> GetAllAsync(int skip = 0, int take = 50, CancellationToken ct = default)
    {
        return await _db.BackgroundJobs
            .Include(j => j.Trader)
            .OrderByDescending(j => j.CreatedAt)
            .Skip(skip)
            .Take(take)
            .ToListAsync(ct);
    }

    public async Task<BackgroundJob?> GetNextPendingJobAsync(JobType type, CancellationToken ct = default)
    {
        return await _db.BackgroundJobs
            .Where(j => j.JobType == type && j.Status == JobStatus.Pending)
            .OrderBy(j => j.CreatedAt)
            .FirstOrDefaultAsync(ct);
    }

    public async Task AddAsync(BackgroundJob job, CancellationToken ct = default)
    {
        _db.BackgroundJobs.Add(job);
        await _db.SaveChangesAsync(ct);
    }

    public async Task UpdateAsync(BackgroundJob job, CancellationToken ct = default)
    {
        _db.BackgroundJobs.Update(job);
        await _db.SaveChangesAsync(ct);
    }

    public async Task ResetHungJobsAsync(CancellationToken ct = default)
    {
        var cutoff = DateTime.UtcNow.AddMinutes(-15);
        await _db.BackgroundJobs
            .Where(j => j.Status == JobStatus.InProgress && j.StartedAt < cutoff)
            .ExecuteUpdateAsync(s => s
                .SetProperty(j => j.Status, JobStatus.Pending)
                .SetProperty(j => j.StartedAt, (DateTime?)null), ct);
    }
}
