using Insight.Agent.Extensions;
using Insight.Agent.Network;
using Insight.Agent.Network.Handlers;
using Insight.Agent.Services;
using Insight.Domain.Constants;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Vaitr.Network;
using Vaitr.Network.Hosting;

namespace Insight.Agent.Windows;

internal class Program
{
    public static async Task Main(string[] args)
    {
        var builder = Host.CreateDefaultBuilder(args);
        builder.UseWindowsService();
        builder.UseSystemd();

        builder.ConfigureAppConfiguration(config =>
        {
            config.Defaults();
        });

        builder.ConfigureLogging(options =>
        {
            options.ClearProviders();
            options.SetMinimumLevel(LogLevel.Trace);

            options.AddSimpleConsole(options =>
            {
                options.IncludeScopes = true;
                options.SingleLine = true;
                options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
            });

            options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/agent_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
        });

        builder.ConfigureServices((host, services) =>
        {
            // HOST-SERVICES
            services.AddHostedService<UpdateService>();
            services.AddHostedService<TrapService>();

            // SERVICES (WINDOWS)
            if (OperatingSystem.IsWindows()) services.AddHostedService<EventService>();
            if (OperatingSystem.IsWindows()) services.AddSingleton<ScriptService>();

            // AGENT NETWORKING
            services.UseHostedClient<AgentSession, IMessage>(options =>
            {
                options.Host = host.Configuration.GetValue<string?>(Appsettings.ServerHost) ?? throw new Exception($"{Appsettings.ServerHost} value not set (appsettings)");
                options.Port = host.Configuration.GetValue<int?>(Appsettings.ServerPort) ?? throw new Exception($"{Appsettings.ServerPort} value not set (appsettings)");
                options.Keepalive = 10000;
                options.Timeout = 30000;

                options.Compression = true;
                options.Encryption = Encryption.Tls12;

                options.UseSerializer<AgentSession, IMessage, MemPackSerializer<IMessage>>();
            });

            services.AddSingleton<IMessageHandler<AgentSession>, CustomHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, ProxyHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, AuthenticationHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, DriveHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, InterfaceHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, MainboardHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, MemoryHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, OperationSystemHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, PrinterHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, ProcessorHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, ServiceHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, SessionHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, SoftwareHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, StoragePoolHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, SystemInfoHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, UpdateHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, UserHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, VideocardHandler>();
            services.AddSingleton<IMessageHandler<AgentSession>, VirtualMaschineHandler>();
            

            // GLOBAL DEPENDENCIES
            //services.AddSingleton<Bus>();
            services.AddTransient(provider => new HttpClient(new HttpClientHandler
            {
                ClientCertificateOptions = ClientCertificateOption.Manual,
                ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true
            }));
        });

        var host = builder.Build();
        await host.RunAsync().ConfigureAwait(false);
    }
}