using FluentValidation;
using IWS5.Importer.Abstractions.FileSystem;
using IWS5.DatabaseAccess.Interfaces;
using IWS5.DatabaseAccess.Interfaces.Importer;
using IWS5.DatabaseAccess.IwsDataContext;
using IWS5.DatabaseAccess.Repositories.Importer;
using IWS5.Importer.Abstractions.Interfaces;
using IWS5.Importer.Abstractions.Services;
using IWS5.Importer.Worker.Conversion;
using IWS5.Importer.Worker.Extensions;
using IWS5.Importer.Worker.FileSystem;
using IWS5.Importer.Worker.Processors;
using IWS5.Importer.Worker.Services;
using IWS5.Importer.Worker.Validation;
using IWS5.Importer.Worker.Workers;
using IWS5.Importer.Worker.Xml;
using IWS5.Services.ImporterService;
using Microsoft.EntityFrameworkCore;
using Serilog;
using System.Text;
using FolderFieldService = IWS5.Services.ImporterService.FolderFieldService;
using IFolderFieldService = IWS5.Importer.Abstractions.Services.IFolderFieldService;
using IProcessRepository = IWS5.DatabaseAccess.Interfaces.Importer.IProcessRepository;
using IProcessService = IWS5.Importer.Abstractions.Services.IProcessService;
using IWorkItemService = IWS5.Importer.Abstractions.Services.IWorkItemService;
using ProcessRepository = IWS5.DatabaseAccess.Repositories.Importer.ProcessRepository;
using ProcessService = IWS5.Services.ImporterService.ProcessService;
using WorkItemService = IWS5.Services.ImporterService.WorkItemService;
using IDocumentCabinetRepository = IWS5.DatabaseAccess.Interfaces.Importer.IDocumentCabinetRepository;
using IWS5.DatabaseAccess.Repositories;


Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
// Build configuration
IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true)
    .Build();

CorrelationIdEnricher.SetCorrelationId(Guid.NewGuid().ToString());

var logDir = configuration.GetValue<string>("ImportSettings:LogDir") ?? @"C:\Logs\Importer";
Directory.CreateDirectory(logDir);
var logFilePath = Path.Combine(logDir, "importer-.log");

IHost host = Host.CreateDefaultBuilder(args)
    .UseSerilog((context, services, loggerConfig) =>
    {
        loggerConfig
            .MinimumLevel.Information()

            .MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", Serilog.Events.LogEventLevel.Warning)
            .MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Warning)
            .MinimumLevel.Override("Microsoft.Hosting.Lifetime", Serilog.Events.LogEventLevel.Warning)

            .Enrich.With(new CorrelationIdEnricher())

            .WriteTo.Console(
                outputTemplate:
                "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {CorrelationId}{NewLine}{Exception}"
            )

            .WriteTo.File(
                path: logFilePath,
                rollingInterval: RollingInterval.Day,
                retainedFileCountLimit: 14,
                encoding: Encoding.UTF8,
                outputTemplate:
                "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} | {Level} | {Message:lj} | {Exception} | {CorrelationId}{NewLine}"
            );
    })
    .ConfigureServices((context, services) =>
    {
        var config = context.Configuration;

        services.AddSingleton<Serilog.ILogger>(sp => Log.Logger);
        // Register Database Context
        var cs = config.GetConnectionString(GreenfieldPd2015Context.ConnectionStringName);
        if (string.IsNullOrWhiteSpace(cs))
            throw new InvalidOperationException($"Missing connection string '{GreenfieldPd2015Context.ConnectionStringName}'");

        services.AddDbContextFactory<GreenfieldPd2015Context>(options =>
            options.UseSqlServer(cs, o => o.UseCompatibilityLevel(100)));

        services.AddDbContext<GreenfieldPd2015Context>(options =>
            options.UseSqlServer(cs, o => o.UseCompatibilityLevel(100)));

        // Register Repositories and Services
        services.AddScoped<IProcessRepository, ProcessRepository>();
        services.AddScoped<IProcessService, ProcessService>();
        services.AddScoped<IWorkItemRepository, WorkItemRepository>();
        services.AddScoped<IWorkItemService, WorkItemService>();
        services.AddScoped<IXmlParser, XmlParser>();
        services.AddScoped<IFileImportProcessor, FileImportProcessor>();
        services.AddScoped<IFileMover, FileMover>();
        services.AddScoped<IWorkItemProcessor, WorkItemProcessor>();
        services.AddScoped<IFolderMover, FolderMover>();
        services.AddScoped<IFileHelper, FileHelper>();
        services.AddScoped<IFileCleaner, FileCleaner>();
        services.AddScoped<IDocumentValidator, DocumentValidator>();
        services.AddScoped<IXmlValidator, XmlValidator>();
        services.AddScoped<IFolderFieldRepository, FolderFieldRepository>();
        services.AddScoped<IFolderFieldService, FolderFieldService>();
        services.AddScoped<IDocumentFieldRepository, DocumentFieldRepository>();
        services.AddScoped<IDocumentFieldService, DocumentFieldService>();
        services.AddScoped<IDocumentCabinetService, DocumentCabinetService>();
        services.AddScoped<IDocumentCabinetRepository, IWS5.DatabaseAccess.Repositories.Importer.DocumentCabinetRepository>();
        services.AddSingleton<IFileConverter, WordFileConverter>();
        services.AddSingleton<IFileConverter, ExcelFileConverter>();
        services.AddSingleton<IFileConverter, PowerPointFileConverter>();
        services.AddSingleton<IFileConverter, ImageFileConverter>();
        services.AddSingleton<IFileConverter, TiffFileConverter>();
        services.AddScoped<IFileConverterService, FileConverterService>();
        services.AddTransient<IPdfPageGenerator<List<(string filePath, string reason)>>, ErrorReportPdfPageGenerator>();
        services.AddSingleton<IGeneralImportSettingsProvider, GeneralImportSettingsProvider>();
        services.AddScoped<IGeneralImportSettingsRepository, GeneralImportSettingsRepository>();
        services.AddScoped<IProcessImportRuleRepository, ProcessImportRuleRepository>();
        services.AddScoped<IWS5.DatabaseAccess.Interfaces.IDocumentCabinetRepository, IWS5.DatabaseAccess.Repositories.DocumentCabinetRepository>();
        services.AddScoped<IRightsRepository, RightsRepository>();
        services.AddScoped<IQueueRepository, QueueRepository>();
        services.AddScoped<IButtonRepository, ButtonRepository>();
        services.AddScoped<IDocumentCabinetDefinitionRepository, DocumentCabinetDefinitionRepository>();
        services.AddScoped<IEventDefinitionRepository, EventDefinitionRepository>();
        services.AddScoped<IFieldDefinitionRepository, FieldDefinitionRepository>();
        services.AddScoped<ITriggerDefinitionRepository, TriggerDefinitionRepository>();
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IDocumentRepository, DocumentRepository>();
        services.AddScoped<IWorkItemReferenceRepository, WorkItemReferenceRepository>();
        services.AddScoped<IWS5.DatabaseAccess.Interfaces.IProcessRepository, IWS5.DatabaseAccess.Repositories.ProcessRepository>();

        foreach (var item in AssemblyScanner.FindValidatorsInAssembly(typeof(IWS5.Services.ProcessService).Assembly).Where(v => v.ValidatorType.Namespace?.StartsWith("IWS5.Services.Validators.IAdmin") == false))
        {
            services.AddScoped(item.InterfaceType, item.ValidatorType);
        }

        services.AddMemoryCache();

        // Register Worker Service
        services.AddHostedService<FileImportWorker>();
        services.AddHostedService<ArchiveCleanupWorker>();
    })
    .Build();

using (var scope = host.Services.CreateScope())
{
    var repo = scope.ServiceProvider.GetRequiredService<IGeneralImportSettingsRepository>();
    var provider = scope.ServiceProvider.GetRequiredService<IGeneralImportSettingsProvider>();

    var settings = await repo.GetGeneralSettingsAsync();
    if (settings == null) throw new InvalidOperationException("Settings not found in DB.");
    provider.Set(settings);
}

string license_key = "Ngo9BigBOggjHTQxAR8/V1NNaF5cWWJCf1FpRmJGdld5fUVHYVZUTXxaS00DNHVRdkdmWXpfdHRdR2VYV0FxXkZWYUA=";
if (license_key != null && license_key != string.Empty)
    Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(license_key);


await host.RunAsync();
Log.CloseAndFlush();
