using JobTrackerApi.Data;
using Microsoft.EntityFrameworkCore;

namespace JobTrackerApi.Services;

// Applies deterministic auto-ghost transitions only when explicitly enabled.
public sealed class RulesHostedService(
    BackgroundTenantRunner tenants,
    IConfiguration configuration,
    ILogger<RulesHostedService> logger,
    IStartupReadiness startupReadiness,
    TimeProvider timeProvider) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await startupReadiness.WaitUntilReadyAsync(stoppingToken);
        if (!configuration.GetValue("Workers:RulesEnabled", false))
        {
            logger.LogInformation("Rules worker disabled (Workers:RulesEnabled=false).");
            return;
        }

        await Task.Delay(TimeSpan.FromSeconds(2), timeProvider, stoppingToken);
        while (!stoppingToken.IsCancellationRequested)
        {
            await RunOnceAsync(stoppingToken);
            await Task.Delay(TimeSpan.FromMinutes(30), timeProvider, stoppingToken);
        }
    }

    public Task<BackgroundWorkerRunResult> RunOnceAsync(CancellationToken cancellationToken)
    {
        if (!configuration.GetValue("Workers:RulesEnabled", false))
            return Task.FromResult(BackgroundWorkerRunResult.Disabled);

        return tenants.RunForJobOwnersAsync("rules", ProcessOwnerAsync, cancellationToken);
    }

    private async Task ProcessOwnerAsync(IServiceProvider services, CancellationToken cancellationToken)
    {
        var db = services.GetRequiredService<JobTrackerContext>();
        var settings = await RulesEngine.GetSettings(db, cancellationToken);
        var now = timeProvider.GetLocalNow().DateTime;
        var lastMessages = await db.Correspondences
            .GroupBy(message => message.JobApplicationId)
            .Select(group => new { JobApplicationId = group.Key, Last = group.Max(x => x.Date) })
            .ToDictionaryAsync(x => x.JobApplicationId, x => (DateTime?)x.Last, cancellationToken);
        var jobs = await db.JobApplications
            .Where(job => !job.IsDeleted && job.Status != "Ghosted")
            .ToListAsync(cancellationToken);

        foreach (var job in jobs)
        {
            lastMessages.TryGetValue(job.Id, out var lastMessage);
            if (RulesEngine.Evaluate(settings, job, now, lastMessage).ShouldGhost)
                job.Status = "Ghosted";
        }

        await db.SaveChangesAsync(cancellationToken);
    }
}
