using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Platform.Bus;
using Platform.Contract.Profiles.Collectors;
using Platform.Cryptography;
using Platform.Geolocation.IpResolver;
using Platform.Logging.Extensions;

namespace Platform.Services.Collector;

public class CollectorSubscriptionService : BackgroundService
{
    private readonly IBusSubscriber _busSubscriber;
    private readonly IProcessorClient _collectorClient;
    private readonly IPublicIpResolver _hostLocation;
    private readonly ICryptographicService _cryptographicService;
    private readonly CollectorInfo _collectorInfo;
    private readonly ILogger _logger;

    // heartbeat interval should be shorter than a coordinator cache ttl
    private readonly TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(10);

    public CollectorSubscriptionService(
        IBusSubscriber busSubscriber,
        IPublicIpResolver hostLocation,
        ICryptographicService cryptographicService,
        IProcessorClient collectorClient,
        CollectorInfo collectorInfo,
        ILogger<CollectorSubscriptionService> logger)
    {
        _busSubscriber = busSubscriber;
        _collectorClient = collectorClient;
        _hostLocation = hostLocation;
        _cryptographicService = cryptographicService;
        _collectorInfo = collectorInfo;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        var ipAddress = (await _hostLocation.FindPublicIpAddress()).GetAddressBytes();
        var publicKey = _cryptographicService.GetPublicKey();

        _busSubscriber.Subscribe(cancellationToken);

        while (true)
        {
            _logger.Trace($"Send heartbeat '{_collectorInfo.ProcessingTypes}' '{_collectorInfo.Identifier}'");
            if (cancellationToken.IsCancellationRequested) break;

            await _collectorClient.SendToCoordinatorSync(_collectorInfo, ipAddress, publicKey);
            await Task.Delay(_heartbeatInterval, cancellationToken);
        }
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        _cryptographicService.Dispose();
        _busSubscriber.Unsubscribe(cancellationToken);
        return Task.CompletedTask;
    }
}