using JSMR.Application.Jobs;
using JSMR.Domain.Entities;
using JSMR.Domain.Enums;
using Microsoft.EntityFrameworkCore;

namespace JSMR.Infrastructure.Data.Repositories.Jobs;

public sealed class JobProgressWriter(AppDbContext dbContext) : IJobProgressWriter
{
    public async Task SetStepAsync(int jobId, string step, CancellationToken canellationToken)
    {
        Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);

        if (job is null)
            return;

        job.CurrentStep = step;
        job.HeartbeatUtc = DateTime.UtcNow;

        await dbContext.SaveChangesAsync(canellationToken);
    }

    public async Task SetProgressAsync(int jobId, int? current, int? total, CancellationToken canellationToken)
    {
        Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
        
        if (job is null)
            return;

        job.ProgressCurrent = current;
        job.ProgressTotal = total;
        job.HeartbeatUtc = DateTime.UtcNow;

        await dbContext.SaveChangesAsync(canellationToken);
    }

    public async Task SetHeartbeatAsync(int jobId, CancellationToken canellationToken)
    {
        Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);
        
        if (job is null)
            return;

        job.HeartbeatUtc = DateTime.UtcNow;

        await dbContext.SaveChangesAsync(canellationToken);
    }

    public async Task CompleteAsync(int jobId, string? summary, CancellationToken canellationToken)
    {
        Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);

        if (job is null)
            return;

        job.Status = JobStatus.Succeeded;
        job.CompletedUtc = DateTime.UtcNow;
        job.HeartbeatUtc = DateTime.UtcNow;
        job.ResultSummary = summary;
        job.CurrentStep = "Completed";

        await dbContext.SaveChangesAsync(canellationToken);
    }

    public async Task FailAsync(int jobId, string error, CancellationToken canellationToken)
    {
        Job? job = await dbContext.Jobs.FirstOrDefaultAsync(x => x.Id == jobId, canellationToken);

        if (job is null)
            return;

        job.Status = JobStatus.Failed;
        job.CompletedUtc = DateTime.UtcNow;
        job.HeartbeatUtc = DateTime.UtcNow;
        job.Error = error;
        job.CurrentStep = "Failed";

        await dbContext.SaveChangesAsync(canellationToken);
    }
}