//
//  ServiceCollectionExtensions.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Packets;
using NosSmooth.Packets.Extensions;
namespace NosSmooth.Core.Extensions;
/// 
/// Contains extension methods for .
/// 
public static class ServiceCollectionExtensions
{
    /// 
    /// Adds base packet and command handling for nostale client.
    /// 
    /// The service collection to register the responder to.
    /// Custom types of packets to serialize and deserialize.
    /// The collection.
    public static IServiceCollection AddNostaleCore
    (
        this IServiceCollection serviceCollection,
        params Type[] additionalPacketTypes
    )
    {
        serviceCollection
            .TryAddSingleton();
        serviceCollection.AddPacketSerialization();
        serviceCollection.AddSingleton();
        return serviceCollection;
    }
    /// 
    /// Adds the specified packet responder that will be called upon receiving the given event.
    /// 
    /// The service collection to register the responder to.
    /// The type of the responder.
    /// Thrown if the type of the responder is incorrect.
    /// The collection.
    public static IServiceCollection AddPacketResponder
    (
        this IServiceCollection serviceCollection
    )
        where TPacketResponder : class, IPacketResponder
    {
        return serviceCollection.AddPacketResponder(typeof(TPacketResponder));
    }
    /// 
    /// Adds the specified packet responder that will be called upon receiving the given event.
    /// 
    /// The service collection to register the responder to.
    /// The type of the responder.
    /// The collection.
    /// Thrown if the type of the responder is incorrect.
    public static IServiceCollection AddPacketResponder
    (
        this IServiceCollection serviceCollection,
        Type responderType
    )
    {
        if (responderType.GetInterfaces().Any(i => i == typeof(IEveryPacketResponder)))
        {
            return serviceCollection.AddScoped(typeof(IEveryPacketResponder), responderType);
        }
        if (!responderType.GetInterfaces().Any(
                i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketResponder<>)
            ))
        {
            throw new ArgumentException(
                $"{nameof(responderType)} should implement IPacketResponder.",
                nameof(responderType));
        }
        var responderTypeInterfaces = responderType.GetInterfaces();
        var responderInterfaces = responderTypeInterfaces.Where
        (
            r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(IPacketResponder<>)
        );
        foreach (var responderInterface in responderInterfaces)
        {
            serviceCollection.AddScoped(responderInterface, responderType);
        }
        return serviceCollection;
    }
    /// 
    /// Adds the specified command handler.
    /// 
    /// The service collection to register the responder to.
    /// The type of the command.
    /// Thrown if the type of the responder is incorrect.
    /// The collection.
    public static IServiceCollection AddCommandHandler
    (
        this IServiceCollection serviceCollection
    )
        where TCommandHandler : class, ICommandHandler
    {
        return serviceCollection.AddCommandHandler(typeof(TCommandHandler));
    }
    /// 
    /// Adds the specified command handler.
    /// 
    /// The service collection to register the responder to.
    /// The type of the command handler.
    /// The collection.
    /// Thrown if the type of the responder is incorrect.
    public static IServiceCollection AddCommandHandler
    (
        this IServiceCollection serviceCollection,
        Type commandHandlerType
    )
    {
        if (!commandHandlerType.GetInterfaces().Any(
                i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>)
            ))
        {
            throw new ArgumentException(
                $"{nameof(commandHandlerType)} should implement ICommandHandler.",
                nameof(commandHandlerType));
        }
        var handlerTypeInterfaces = commandHandlerType.GetInterfaces();
        var handlerInterfaces = handlerTypeInterfaces.Where
        (
            r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(ICommandHandler<>)
        );
        foreach (var handlerInterface in handlerInterfaces)
        {
            serviceCollection.AddScoped(handlerInterface, commandHandlerType);
        }
        return serviceCollection;
    }
}