using Pgo.Backend.Models;
using System.Collections.Concurrent;

namespace Pgo.Backend.Services;

public interface IResourcesBackgroundService
{
    BackgroundJobStatus GetJobStatus(string jobId);
    BackgroundJobStatus QueueJob(IRequest request);
}

/// <summary>
/// Service for a simple demo showing some delayed background-like processing of FHIR pref-async requests.
/// Adds a request to the queue, starts processing that and returns a job status on polls at <see cref="RemoteFhirServicesController"/>.
/// </summary>
public class ResourcesBackgroundService(ILogger<ResourcesBackgroundService> logger, IDocumentService bundleService) : IResourcesBackgroundService
{
    private readonly ILogger<ResourcesBackgroundService> _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    private readonly IDocumentService _bundleService = bundleService ?? throw new ArgumentNullException(nameof(bundleService));
    private readonly ConcurrentDictionary<string, BackgroundJobStatus> _jobs = new();    

    public BackgroundJobStatus GetJobStatus(string jobId) =>
       _jobs.TryGetValue(jobId, out var status)
       ? status
       : BackgroundJobStatus.Create(jobId, null, false, $"Job {jobId} unknown.", null);

    public BackgroundJobStatus QueueJob(IRequest request)
    {
        var jobId = Guid.NewGuid().ToString();
        Task.Run(async () =>
        {
            try
            {
                switch (request)
                {
                    case DocumentRequest request:
                        _logger.LogInformation($"Job {jobId} processing.");
                        _jobs[jobId].Success(result: await _bundleService.GetDocumentAsync(request));
                        break;

                    default:
                        _logger.LogError($"Job {jobId} not supported for request {request.GetType().Name}.");
                        _jobs[jobId].Fail("Not supported.");
                        break;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Job {jobId} failed.");
                _jobs[jobId].Fail(ex.Message);
            }                        
        });

        _logger.LogInformation($"Job {jobId} added.");
        return _jobs[jobId] = BackgroundJobStatus.Create(jobId, request);
    }
   
}
