#nullable enable
using System;
using System.Threading;
using System.Threading.Tasks;
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Configuration;
using Baya.Application.Features.Payouts.Commands.GeneratePayoutBatch;
using Mediator;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Baya.Infrastructure.Persistence.Services.Scheduling.Jobs;

/// <summary>
/// Generates the weekly nurse-payout batch (previously admin-manual — <c>nurse_payout_interval_days</c> was seeded
/// but nothing read it, so nurses were paid only when an operator clicked). Scheduled on that cadence, it opens a
/// <c>draft</c> batch over the trailing window; the admin generate trigger remains an override.
///
/// <para><b>Generation only — never money movement.</b> Per the phase's "keep processing human-approved until trust
/// is earned", this schedules <em>batch generation</em>; the irreversible <c>process</c> step stays an explicit
/// admin action. The batch is <b>system-initiated</b> (<see cref="GeneratePayoutBatchCommand.SystemInitiated"/> →
/// null initiator). A quiet week (no eligible bookings) returns a benign failure, logged at debug — not an error.
/// Re-running over an overlapping window is safe: the <c>nurse_payout_booking_links.booking_id</c> UNIQUE prevents
/// re-selecting an already-paid booking.</para>
/// </summary>
internal sealed class WeeklyPayoutGenerationJob(ILogger<WeeklyPayoutGenerationJob> logger) : IRecurringJob
{
    public string Name => "weekly_payout_generation";

    public async ValueTask<TimeSpan> GetIntervalAsync(IServiceProvider services, CancellationToken cancellationToken)
    {
        var config = services.GetRequiredService<IPlatformConfig>();
        var days = await config.GetConfig<int>("nurse_payout_interval_days", cancellationToken);
        return TimeSpan.FromDays(days);
    }

    public async ValueTask RunAsync(IServiceProvider services, CancellationToken cancellationToken)
    {
        var clock = services.GetRequiredService<IDateTimeProvider>();
        var config = services.GetRequiredService<IPlatformConfig>();
        var sender = services.GetRequiredService<ISender>();

        var intervalDays = await config.GetConfig<int>("nurse_payout_interval_days", cancellationToken);
        var periodEnd = DateOnly.FromDateTime(clock.UtcNow.UtcDateTime);
        var periodStart = periodEnd.AddDays(-Math.Max(intervalDays, 1));

        var result = await sender.Send(
            new GeneratePayoutBatchCommand(periodStart, periodEnd) { SystemInitiated = true }, cancellationToken);

        if (result.IsSuccess && result.Result is { } generated)
            logger.LogInformation(
                "Weekly payout generation opened a draft batch of {Count} payout(s) totalling {Total} IRR (awaiting admin process)",
                generated.Batch.PayoutCount, generated.Batch.TotalAmount);
        else
            // Expected on a quiet week (no eligible bookings) — not an operational error.
            logger.LogDebug("Weekly payout generation produced no batch this run (no payout-eligible bookings).");
    }
}
