using NexusShell.Agent;
using NexusShell.Models;

namespace NexusShell.Services.Identity;

public sealed class NexusEnrollmentService
{
    private readonly NexusOrganizationService _organizations;
    private readonly NexusUserProfileService _users;
    private readonly NexusDeviceTrustService _trust;
    private readonly NexusRemoteEnrollmentClient? _remoteEnrollment;
    private NexusDeviceRecord? _cached;
    private NexusRemoteEnrollmentSyncResult? _lastRemoteSync;

    public NexusEnrollmentService(
        NexusOrganizationService organizations,
        NexusUserProfileService users,
        NexusDeviceTrustService trust,
        NexusRemoteEnrollmentClient? remoteEnrollment = null)
    {
        _organizations = organizations;
        _users = users;
        _trust = trust;
        _remoteEnrollment = remoteEnrollment;
    }

    public bool IsEnrolled
    {
        get
        {
            var device = CurrentDevice;
            return device is not null &&
                   !string.IsNullOrWhiteSpace(device.DeviceId) &&
                   device.Status == NexusDeviceEnrollmentStatus.Enrolled;
        }
    }

    public NexusRemoteEnrollmentSyncResult? LastRemoteSync => _lastRemoteSync;

    public NexusDeviceRecord? CurrentDevice => _cached ?? LoadDevice();

    public NexusDeviceRecord? LoadDevice()
    {
        _cached = NexusIdentityStorage.Load<NexusDeviceRecord>(NexusIdentityStorage.DevicePath);
        return _cached;
    }

    public NexusEnrollmentResult Enroll(NexusEnrollmentRequest request, string shellVersion, string agentVersion)
    {
        if (string.IsNullOrWhiteSpace(request.OrganizationId))
        {
            return Fail("Vælg organisation.");
        }

        var catalogOrg = NexusOrganizationCatalog.FindById(request.OrganizationId);
        if (catalogOrg is null)
        {
            return Fail("Ukendt organisation.");
        }

        if (string.IsNullOrWhiteSpace(request.UserName))
        {
            return Fail("Angiv bruger.");
        }

        if (string.IsNullOrWhiteSpace(request.DeviceFriendlyName))
        {
            return Fail("Angiv enhedsnavn.");
        }

        var org = _organizations.SaveFromCatalog(catalogOrg);
        var user = _users.Save(request.UserName, org);

        var now = DateTimeOffset.UtcNow;
        var device = new NexusDeviceRecord
        {
            DeviceId = NexusAgentConfig.GenerateDeviceId(),
            ComputerName = Environment.MachineName,
            FriendlyName = request.DeviceFriendlyName.Trim(),
            Owner = user.DisplayName,
            Organization = org.Name,
            AgentVersion = agentVersion,
            ShellVersion = shellVersion,
            EnrollmentDate = now,
            LastSeen = now,
            Status = NexusDeviceEnrollmentStatus.Enrolled,
        };

        NexusIdentityStorage.Save(NexusIdentityStorage.DevicePath, device);
        _cached = device;
        _trust.InitializeForDevice(device.DeviceId);

        _lastRemoteSync = SyncRemoteEnrollmentAsync(device, request.OrganizationId, shellVersion, agentVersion)
            .GetAwaiter()
            .GetResult();

        return new NexusEnrollmentResult
        {
            Success = true,
            Device = device,
            RemoteSync = _lastRemoteSync,
        };
    }

    public async Task<NexusRemoteEnrollmentSyncResult?> SyncRemoteEnrollmentAsync(CancellationToken ct = default)
    {
        var device = CurrentDevice;
        if (device is null || _remoteEnrollment?.IsConfigured != true)
        {
            return null;
        }

        var org = _organizations.Load();
        var orgId = org?.Id ?? NexusOrganizationCatalog.FindByName(device.Organization)?.Id;
        if (string.IsNullOrWhiteSpace(orgId))
        {
            return NexusRemoteEnrollmentSyncResult.Failed("Organization ID not found for remote sync.");
        }

        _lastRemoteSync = await SyncRemoteEnrollmentAsync(device, orgId, device.ShellVersion, device.AgentVersion, ct);
        return _lastRemoteSync;
    }

    private async Task<NexusRemoteEnrollmentSyncResult> SyncRemoteEnrollmentAsync(
        NexusDeviceRecord device,
        string organizationId,
        string shellVersion,
        string agentVersion,
        CancellationToken ct = default)
    {
        if (_remoteEnrollment?.IsConfigured != true)
        {
            return NexusRemoteEnrollmentSyncResult.Skipped();
        }

        return await _remoteEnrollment.TryRegisterAsync(new RemoteEnrollmentPayload
        {
            DeviceId = device.DeviceId,
            OrganizationId = organizationId,
            UserName = device.Owner,
            DeviceFriendlyName = device.FriendlyName,
            ComputerName = device.ComputerName,
            Os = "Windows",
            ShellVersion = shellVersion,
            AgentVersion = agentVersion,
        }, ct);
    }

    public void SyncAgentConfig(NexusAgentConfig agentConfig)
    {
        var device = CurrentDevice;
        if (device is null || string.IsNullOrWhiteSpace(device.DeviceId))
        {
            return;
        }

        agentConfig.DeviceId = device.DeviceId;
        agentConfig.IsRegistered = true;
        agentConfig.RegisteredAtUtc ??= device.EnrollmentDate;
        agentConfig.Save();
    }

    public void RefreshVersions(string shellVersion, string agentVersion)
    {
        var device = CurrentDevice;
        if (device is null)
        {
            return;
        }

        device.ShellVersion = shellVersion;
        device.AgentVersion = agentVersion;
        device.LastSeen = DateTimeOffset.UtcNow;
        NexusIdentityStorage.Save(NexusIdentityStorage.DevicePath, device);
        _cached = device;
    }

    private static NexusEnrollmentResult Fail(string error) =>
        new() { Success = false, Error = error };
}
