using Avalonia.Threading;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace OTSSignsOrchestrator.Desktop.Services;

/// <summary>
/// Singleton service managing the persistent SignalR connection to the server's FleetHub.
/// All handlers dispatch to the UI thread and republish via <see cref="WeakReferenceMessenger"/>.
/// </summary>
public sealed class ServerSignalRService : IAsyncDisposable
{
    private readonly HubConnection _connection;
    private readonly ILogger<ServerSignalRService> _logger;

    public ServerSignalRService(
        TokenStoreService tokenStore,
        IConfiguration config,
        ILogger<ServerSignalRService> logger)
    {
        _logger = logger;
        var baseUrl = config["ServerBaseUrl"] ?? "https://localhost:5001";

        _connection = new HubConnectionBuilder()
            .WithUrl($"{baseUrl}/hubs/fleet", options =>
            {
                options.AccessTokenProvider = () => Task.FromResult(tokenStore.GetJwt());
            })
            .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(30) })
            .Build();

        RegisterHandlers();

        _connection.Reconnecting += ex =>
        {
            _logger.LogWarning(ex, "SignalR reconnecting...");
            return Task.CompletedTask;
        };

        _connection.Reconnected += connectionId =>
        {
            _logger.LogInformation("SignalR reconnected (connId={ConnectionId})", connectionId);
            return Task.CompletedTask;
        };

        _connection.Closed += ex =>
        {
            _logger.LogWarning(ex, "SignalR connection closed");
            return Task.CompletedTask;
        };
    }

    /// <summary>
    /// Starts the SignalR connection. Call from <c>App.OnFrameworkInitializationCompleted</c>.
    /// Failures are logged but do not throw — automatic reconnect will retry.
    /// </summary>
    public async Task StartAsync()
    {
        try
        {
            await _connection.StartAsync();
            _logger.LogInformation("SignalR connected to FleetHub");
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "SignalR initial connection failed — will retry via automatic reconnect");
        }
    }

    public async Task StopAsync()
    {
        try { await _connection.StopAsync(); }
        catch (Exception ex) { _logger.LogWarning(ex, "Error stopping SignalR connection"); }
    }

    public HubConnectionState State => _connection.State;

    private void RegisterHandlers()
    {
        _connection.On<string, string, string>("SendJobCreated", (jobId, abbrev, jobType) =>
            Dispatcher.UIThread.InvokeAsync(() =>
                WeakReferenceMessenger.Default.Send(
                    new JobCreatedMessage(new(jobId, abbrev, jobType)))));

        _connection.On<string, string, int, string>("SendJobProgressUpdate", (jobId, stepName, pct, logLine) =>
            Dispatcher.UIThread.InvokeAsync(() =>
                WeakReferenceMessenger.Default.Send(
                    new JobProgressUpdateMessage(new(jobId, stepName, pct, logLine)))));

        _connection.On<string, bool, string>("SendJobCompleted", (jobId, success, summary) =>
            Dispatcher.UIThread.InvokeAsync(() =>
                WeakReferenceMessenger.Default.Send(
                    new JobCompletedMessage(new(jobId, success, summary)))));

        _connection.On<string, string>("SendInstanceStatusChanged", (customerId, status) =>
            Dispatcher.UIThread.InvokeAsync(() =>
                WeakReferenceMessenger.Default.Send(
                    new InstanceStatusChangedMessage(new(customerId, status)))));

        _connection.On<string, string>("SendAlertRaised", (severity, message) =>
            Dispatcher.UIThread.InvokeAsync(() =>
                WeakReferenceMessenger.Default.Send(
                    new AlertRaisedMessage(new(severity, message)))));
    }

    public async ValueTask DisposeAsync()
    {
        await _connection.DisposeAsync();
    }
}
