using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Knot.Shared.Kernel;
using System.Security.Cryptography;
using Knot.Contracts.Settings.Application.DTOs;
using Knot.Contracts.Settings.Application.Abstractions;

namespace Knot.Modules.Settings.Application.Settings.Commands;

public record UpdateSettingsCommand(SystemSettingsDto Settings) : ICommand<SystemSettingsDto>;

internal sealed class UpdateSettingsCommandHandler : ICommandHandler<UpdateSettingsCommand, SystemSettingsDto>
{
    private readonly ISettingsService _settingsService;
    private readonly IMediator _mediator;

    public UpdateSettingsCommandHandler(ISettingsService settingsService, IMediator mediator)
    {
        _settingsService = settingsService;
        _mediator = mediator;
    }

    public async Task<Result<SystemSettingsDto>> Handle(UpdateSettingsCommand request, CancellationToken cancellationToken)
    {
        // Enforce WebRTC hierarchy
        if (!request.Settings.WebRtc.Enabled) 
        {
            request.Settings.WebRtc.EnableVideoCalls = false;
            request.Settings.WebRtc.EnableScreenSharing = false;
        }
        else 
        {
            // Master switch always means standard voice calls are available
            request.Settings.WebRtc.EnableVoiceCalls = true;
        }

        if (request.Settings.Federation.Enabled && 
            (string.IsNullOrEmpty(request.Settings.Federation.PrivateKey) || 
             string.IsNullOrEmpty(request.Settings.Federation.PublicKey)))
        {
            using var rsa = RSA.Create(2048);
            request.Settings.Federation.PrivateKey = Convert.ToBase64String(rsa.ExportPkcs8PrivateKey());
            request.Settings.Federation.PublicKey = Convert.ToBase64String(rsa.ExportRSAPublicKey());
        }

        await _settingsService.UpdateSettingsAsync(request.Settings, cancellationToken);
        
        // Notify other modules via Domain Event if needed, but here we can just publish
        await _mediator.Publish(new Knot.Modules.Settings.Domain.Events.SystemSettingsUpdatedDomainEvent(request.Settings), cancellationToken);

        return Result.Success(request.Settings);
    }
}
