using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Http;

using Microsoft.Extensions.Hosting;

using NexusShell.Services.Identity;

using NexusShell.Services.Policy;



namespace NexusShell.Agent;



public sealed class NexusAgentService : IAsyncDisposable

{

    private readonly NexusAgentConfig _config;

    private readonly NexusInventoryService _inventory;

    private readonly NexusHealthService _health;

    private readonly NexusDeviceRegistrationService _registration;

    private readonly NexusHeartbeatDispatcher _heartbeatDispatcher;

    private readonly NexusPresenceService _presence;

    private readonly NexusDeviceStatusService _deviceStatus;

    private readonly NexusAgentRuntimeState _state;

    private readonly NexusPolicyService? _policyService;

    private readonly string _shellVersion;

    private WebApplication? _app;

    private Task? _hostTask;

    private CancellationTokenSource? _hostCts;



    public NexusAgentService(

        NexusAgentConfig config,

        NexusInventoryService inventory,

        NexusHealthService health,

        NexusDeviceRegistrationService registration,

        NexusHeartbeatDispatcher heartbeatDispatcher,

        NexusPresenceService presence,

        NexusDeviceStatusService deviceStatus,

        string shellVersion,

        NexusIdentityService? identity = null,

        NexusPolicyService? policyService = null)

    {

        _config = config;

        _inventory = inventory;

        _health = health;

        _registration = registration;

        _heartbeatDispatcher = heartbeatDispatcher;

        _presence = presence;

        _deviceStatus = deviceStatus;

        _shellVersion = shellVersion;

        _policyService = policyService;

        _state = new NexusAgentRuntimeState(config, shellVersion, identity);

    }

    public NexusAgentRuntimeState State => _state;



    public async Task StartAsync(CancellationToken cancellationToken = default)

    {

        NexusAgentLogger.Info("startup", $"Nexus Agent {NexusAgentConfig.AgentVersion} starting on {_config.LocalApiUrl}");



        _hostCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

        _app = BuildWebApp();

        _hostTask = _app.RunAsync(_hostCts.Token);

        _ = _hostTask.ContinueWith(

            static t => NexusAgentLogger.Warn("startup", t.Exception?.GetBaseException().Message ?? "Agent host stopped"),

            TaskContinuationOptions.OnlyOnFaulted);



        _ = Task.Run(async () =>

        {

            await Task.Delay(500, cancellationToken);

            await _registration.TryRegisterAsync(cancellationToken);

            await _heartbeatDispatcher.SendNowAsync(cancellationToken);

        }, cancellationToken);



        NexusAgentLogger.Info("startup", $"Local API listening — DeviceId {_config.DeviceId}");

    }



    public async Task StopAsync()

    {

        NexusAgentLogger.Info("shutdown", "Nexus Agent stopping");



        if (_hostCts is not null)

        {

            await _hostCts.CancelAsync();

        }



        if (_hostTask is not null)

        {

            try

            {

                await _hostTask;

            }

            catch (OperationCanceledException)

            {

                // expected on shutdown

            }

        }



        if (_app is not null)

        {

            await _app.DisposeAsync();

        }



        _heartbeatDispatcher.Dispose();



        NexusAgentLogger.Info("shutdown", "Nexus Agent stopped");

    }



    public async ValueTask DisposeAsync() => await StopAsync();



    private WebApplication BuildWebApp()

    {

        var builder = WebApplication.CreateSlimBuilder(new WebApplicationOptions

        {

            Args = Array.Empty<string>(),

            ContentRootPath = AppContext.BaseDirectory,

        });



        builder.WebHost.UseUrls(_config.LocalApiUrl);



        var app = builder.Build();



        app.MapGet("/agent/status", () => Results.Json(_state.GetStatus()));

        app.MapGet("/agent/device", () => Results.Json(_state.GetDevice()));

        app.MapGet("/agent/inventory", () => Results.Json(_state.GetInventory(_inventory)));

        app.MapGet("/agent/health", () => Results.Json(_state.GetHealth(_health)));

        app.MapGet("/agent/identity", () => Results.Json(_state.GetIdentity()));

        app.MapGet("/agent/device-profile", () => Results.Json(_state.GetDeviceProfile(_inventory, _health)));

        app.MapGet("/agent/trust", () => Results.Json(_state.GetTrust()));

        app.MapGet("/agent/policies", () => Results.Json(_state.GetPolicies(_policyService)));

        app.MapGet("/agent/presence", () => Results.Json(_presence.CaptureSnapshot()));

        app.MapGet("/agent/device-status", () => Results.Json(_deviceStatus.CaptureSnapshot()));



        return app;

    }

}


