using Hangfire;
using KArtSell.BuildingBlocks.Time;
using KArtSell.Modules.ModelOperations.ShadowRun;
using Microsoft.Extensions.Logging;

namespace KArtSell.Host.Jobs;

/// <summary>
/// Historical batch shadow run: processes full 1-year past data in single job.
///
/// Usage: Manually trigger or schedule daily at off-peak (e.g., 21:00 KST).
/// Invokes ShadowRunJob with 1-year date range to complete Phase 1 validation.
///
/// Idempotency: Each run generates unique RunId + IdempotencyKey; safe to retry.
/// </summary>
public sealed class HistoricalBatchShadowRunJob(
    IBackgroundJobClient backgroundJobClient,
    ShadowRunQueries queries,
    IClock clock,
    ILogger<HistoricalBatchShadowRunJob> logger)
{
    private static readonly Action<ILogger, DateOnly, DateOnly, Exception?> LogHistoricalBatchStarted =
        LoggerMessage.Define<DateOnly, DateOnly>(
            LogLevel.Information,
            new EventId(1, nameof(LogHistoricalBatchStarted)),
            "Historical batch shadow run initiated: {Start:yyyy-MM-dd} to {End:yyyy-MM-dd}");

    private static readonly Action<ILogger, Guid, string, Exception?> LogBatchJobEnqueued =
        LoggerMessage.Define<Guid, string>(
            LogLevel.Information,
            new EventId(2, nameof(LogBatchJobEnqueued)),
            "Historical batch job {RunId} enqueued; Hangfire job: {JobId}");

    /// <summary>
    /// Execute historical batch: load past 1 year of data and validate in single job.
    /// </summary>
    [Queue("q-research")]
    [DisableConcurrentExecution(timeoutInSeconds: 300)]  // 5 min to queue; job itself has 30 min
    public async Task ExecuteAsync(CancellationToken cancellationToken = default)
    {
        // Use all-models sentinel for batch
        var targetModelId = Guid.Empty;

        // Calculate 1-year window: 252 trading days ≈ 365 calendar days
        var endDate = DateOnly.FromDateTime(clock.UtcNow.Date);
        var startDate = endDate.AddDays(-365);  // 1 year back

        LogHistoricalBatchStarted(logger, startDate, endDate, null);

        try
        {
            // Create unique run
            var runId = Guid.NewGuid();
            var idempotencyKey = Guid.NewGuid();
            var correlationId = Guid.NewGuid();

            // Pre-insert shadow_run with "Queued" status
            var createdAt = clock.UtcNow;
            await queries.InsertShadowRunQueuedAsync(
                runId,
                targetModelId,
                startDate,
                endDate,
                createdAt,
                CancellationToken.None);

            // Enqueue ShadowRunJob with 1-year range
            var command = new ShadowRunCommand(
                ModelId: targetModelId,
                CorrelationId: correlationId,
                IdempotencyKey: idempotencyKey,
                WindowStartDate: startDate,
                WindowEndDate: endDate,
                PhaseFilter: MarketPhaseFilter.All);

            var jobId = backgroundJobClient.Enqueue<ShadowRunJob>(
                job => job.ExecuteAsync(command, CancellationToken.None));

            LogBatchJobEnqueued(logger, runId, jobId, null);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Historical batch shadow run failed to enqueue");
            throw;
        }
    }
}
