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

namespace Host.Application.Federation.Commands;

public record HandshakeRequest(string Domain, string PublicKey, RemoteCapabilities Capabilities);
public record HandshakeResponse(string Domain, string PublicKey, RemoteCapabilities Capabilities, string Status);

public record HandshakeFederationCommand(HandshakeRequest Request) : ICommand<HandshakeResponse>;

internal sealed class HandshakeFederationCommandHandler : ICommandHandler<HandshakeFederationCommand, HandshakeResponse>
{
    private readonly ISettingsService _settingsService;

    public HandshakeFederationCommandHandler(ISettingsService settingsService)
    {
        _settingsService = settingsService;
    }

    public async Task<Result<HandshakeResponse>> Handle(HandshakeFederationCommand request, CancellationToken cancellationToken)
    {
        var allSettings = await _settingsService.GetSettingsAsync(cancellationToken);
        var conf = allSettings.Federation;

        if (!conf.Enabled)
            return Result.Failure<HandshakeResponse>(new Error(Errors.DisabledByAdmin, "Federation is disabled or keys not generated."));

        if (string.IsNullOrEmpty(request.Request.Domain) || string.IsNullOrEmpty(request.Request.PublicKey))
            return Result.Failure<HandshakeResponse>(new Error("Request.Invalid", "Domain and PublicKey required."));

        // Проверка разрешенности домена (белый список)
        var allowedList = conf.AllowedDomains ?? new List<FederationDomainConfig>();
        var domainConfig = allowedList.FirstOrDefault(d => d.IsEnabled && d.Domain.Equals(request.Request.Domain, StringComparison.OrdinalIgnoreCase));
        
        if (domainConfig == null)
            return Result.Failure<HandshakeResponse>(new Error("Federation.DomainNotAllowed", "Your domain is not in our allowlist."));

        // Сохраняем полученные данные о партнере (Capabilities и Ключ) в кэш настроек
        domainConfig.PublicKey = request.Request.PublicKey;
        domainConfig.Capabilities = request.Request.Capabilities;
        
        await _settingsService.UpdateSettingsAsync(allSettings, cancellationToken);

        // Наш ответ с нашими возможностями
        var ourCapabilities = new RemoteCapabilities
        {
            AllowMedia = allSettings.Messages.AllowMedia,
            AllowPolls = allSettings.Messages.AllowPolls,
            AllowVoiceMessages = allSettings.Messages.AllowVoiceMessages,
            AllowVideoCalls = allSettings.WebRtc.EnableVideoCalls,
            AllowScreenSharing = allSettings.WebRtc.EnableScreenSharing
        };

        var response = new HandshakeResponse(
            allSettings.System.DomainUrl,
            conf.PublicKey ?? string.Empty,
            ourCapabilities,
            "Accepted"
        );
        
        return Result.Success(response);
    }
}
