using Microsoft.AspNetCore.SignalR;
using RobotNet.RobotManager.Hubs;
using RobotNet.RobotShares.Dtos;

namespace RobotNet.RobotManager.Services.Traffic;

public class TrafficPublisher(TrafficManager TrafficManager, IHubContext<TrafficHub> TrafficHub, LoggerController<TrafficPublisher> Logger) : IHostedService
{
    private const int intervalTime = 2000;
    private WatchTimer<TrafficPublisher>? Timer;

    public readonly Dictionary<Guid, string> TrafficMapActive = [];

    public List<TrafficAgentDto> GetAgents(Guid MapId)
    {
        if (TrafficManager.TrafficMaps.TryGetValue(MapId, out TrafficMap? trafficMap))
        {
            List<TrafficAgentDto> agents = [];
            List<TrafficNodeDto> lockedNodes = [];
            foreach (var agent in trafficMap.Agents)
            {
                if (trafficMap.Locked.TryGetValue(agent.Key, out List<TrafficNodeDto>? locked) && locked is not null) lockedNodes = locked;
                var trafficConflict = trafficMap.Conflicts.FirstOrDefault(c => c.AgentRequest.Robot.SerialNumber == agent.Key);
                agents.Add(new()
                {
                    RobotId = agent.Key,
                    State = agent.Value.State,
                    ReleaseNode = agent.Value.ReleaseNode,
                    Nodes = agent.Value.Nodes,
                    InNode = agent.Value.Nodes[agent.Value.InNodeIndex],
                    LockedNodes = lockedNodes,
                    SubNodes = agent.Value.SubNodes,
                    GiveWayNodes = agent.Value.GivewayNodes,
                    ConflictAgentId = trafficConflict is null ? "" : trafficConflict.AgentConflict.Robot.SerialNumber,
                    ConflictNode = trafficConflict?.NodeConflict,
                });
            }
            foreach (var agent in trafficMap.Locked)
            {
                if (agents.Any(a => a.RobotId == agent.Key)) continue;
                agents.Add(new()
                {
                    RobotId = agent.Key,
                    LockedNodes = agent.Value,
                });
            }
            return agents;
        }
        return [];
    }

    private void TimerHandler()
    {
        try
        {
            foreach (var mapActive in TrafficMapActive)
            {
                var agents = GetAgents(mapActive.Key);
                if (agents.Count > 0)
                {
                    var pub = Task.Run(async () => await TrafficHub.Clients.Client(mapActive.Value).SendAsync("TrafficAgentUpdated", agents));
                    pub.Wait();
                }
            }
        }
        catch (Exception ex)
        {
            Logger.Error($"Robot Publisher Error: {ex}");
        }
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        Timer = new(intervalTime, TimerHandler, Logger);
        Timer.Start();
        await Task.Yield();
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        Timer?.Dispose();
        return Task.CompletedTask;
    }
}
