using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.Core.Repositories.Interfaces.Job;
using PARR.Core.Repositories.Interfaces.Schedule;
using PARR.Core.Repositories.Interfaces.TaskRepositories;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.DAL.Configurations.DbSettings;
using PARR.DAL.Context;
using PARR.DAL.Repositories;
using PARR.DAL.Repositories.Job;
using PARR.DAL.Repositories.Schedule;
using PARR.DAL.Repositories.TaskRepositories;
using PARR.DAL.Repositories.Unit;
using PARR.Domain.Settings;

namespace PARR.DAL
{
    public static class DependencyInjection
    {
        // TODO: Избавиться от лишнего


        /// <summary>
        /// Устанавливает Dal сервисы (1)
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddDalServices(this IServiceCollection services, IConfiguration configuration)
        {
            //.EnableSensitiveDataLogging() - вкл подробное логирование при применении миграций, на проде выключить
            services.AddDbContext<DataContext>(opt =>
              opt
                .EnableSensitiveDataLogging()
                .UseNpgsql(configuration.GetConnectionString("DefaultConnection"))
            );


            // -----------------
            // TODO: Переделать все репозитории, которые работаютс с PG с AddTransient на AddScoped
            // -----------------



            // Entity services
            //services.AddTransient<IHostService, HostService>();
            //services.AddTransient<IWorkGroupService, WorkGroupService>();
            //services.AddTransient<IApplicationService, ApplicationService>();
            //services.AddTransient<IApplicationTypeService, ApplicationTypeService>();
            //services.AddTransient<IApplicationInHostService, ApplicationInHostService>();
            //services.AddTransient<IApplicationsInWorkService, ApplicationsInWorkService>();
            //services.AddTransient<IApplicationService, ApplicationService>();
            services.AddTransient<IProcessRepository, ProcessRepository>();
            services.AddTransient<ISubprocessRepository, SubprocessRepository>();
            services.AddTransient<ITnkRepository, TnkRepository>();
            services.AddTransient<ITemplateRepository, TemplateRepository>();
            services.AddTransient<IStatusTemplateRepository, StatusTemplateRepository>();
            services.AddTransient<IRobotHistoryLevelRepository, RobotHistoryLevelRepository>();
            services.AddTransient<IRobotStatusRepository, RobotStatusRepository>();
            services.AddTransient<IRobotRepository, RobotRepository>();
            services.AddTransient<IRobotConfigurationRepository, RobotConfigurationRepository>();
            services.AddTransient<IRobotHistoryRepository, RobotHistoryRepository>();
            services.AddTransient<IEsppSchTypeConfigRepository, EsppSchTypeConfigRepository>();
            services.AddTransient<IAgentHistoryRepository, AgentHistoryRepository>();
            services.AddTransient<IOrderRepository, OrderRepository>();
            services.AddTransient<IOrderStatusRepository, OrderStatusRepository>();
            services.AddTransient<IUserRepository, UserRepository>();
            services.AddTransient<IRoleRepository, RoleRepository>();
            services.AddTransient<ITaskStatusRepository, TaskStatusRepository>();
            //services.AddTransient<IEkStatusService, EkStatusService>();
            services.AddTransient<IEsppSchTypeScheduleRepository, EsppSchTypeScheduleRepository>();
            services.AddTransient<IWeekendDayRepository, WeekendDayRepository>();
            services.AddTransient<IDistributionPeriodRepository, DistributionPeriodRepository>();
            services.AddTransient<IEsppSchTypeValueRepository, EsppSchTypeValueRepository>();
            //services.AddTransient<IResponseAreaService, ResponseAreaService>();
            services.AddTransient<ITemplateHistoryRepository, TemplateHistoryRepository>();
            services.AddTransient<IParrComponentRepository, ParrComponentRepository>();
            services.AddTransient<ITemplateStatusTypeRepository, TemplateStatusTypeRepository>();

            #region Schedule 

            services.AddTransient<IScheduleExcludeTypeRepository, ScheduleExcludeTypeRepository>();
            services.AddTransient<IScheduleExcludeTypeCalendarRepository, ScheduleExcludeTypeCalendarRepository>();

            #endregion

            #region Unit

            services.AddTransient<IUnitRepository, UnitRepository>();
            services.AddTransient<IUnitFieldValueRepository, UnitFieldValueRepository>();
            services.AddTransient<IUnitFieldRepository, UnitFieldRepository>();
            services.AddTransient<IUnitInUnitRepository, UnitInUnitRepository>();
            services.AddTransient<IUnitInValueRepository, UnitInValueRepository>();
            services.AddTransient<IUnitRegionalEkPtkGroupRepository, UnitRegionalEkPtkGroupRepository>();
            services.AddTransient<IUnitKiiUnitRepository, UnitKiiUnitRepository>();

            #endregion

            #region Job

            services.AddTransient<IJobRepository, JobRepository>();
            services.AddTransient<IJobGroupRepository, JobGroupRepository>();
            services.AddTransient<IJobGroupTypeRepository, JobGroupTypeRepository>();
            services.AddTransient<IJobUnitFilterRepository, JobUnitFilterRepository>();
            services.AddTransient<IFieldFilterRepository, FieldFilterRepository>();
            services.AddTransient<IJobUnitFilterRepository, JobUnitFilterRepository>();
            services.AddTransient<IJobAutoControlRepository, JobAutoControlRepository>();

            #endregion

            #region Task

            services.AddScoped<ITaskErrorRepository, TaskErrorRepository>();
            services.AddScoped<ITaskRepository, TaskRepository>();
            services.AddScoped<ITaskTypeRepository, TaskTypeRepository>();

            #endregion

            //services.AddTransient<INextRunModifierService, NextRunModifierService>();

            #region NextRun Services

            //services.AddTransient<IEsppScheduleTransformService, EsppScheduleTransformService>();
            //services.AddTransient<ITemplateDistributor, TemplateDistributor>();
            //services.AddTransient<INextRunService, NextRunService>();

            #endregion


            #region DomainServces
            //services.AddTransient<IShortcodesService, ShortcodesService>();
            //services.AddTransient<IUnitFilterService, UnitFilterService>();
            //services.AddTransient<IMatchingStatusService, MatchingStatusService>();

            //services.Configure<UnitFilterServiceOptions>(options =>
            //{
            //    options.LoadBatchSize = 50;
            //});
            #endregion


        }

        /// <summary>
        /// Добавляет конфигурацию Dal (2)
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IConfigurationBuilder AddDalConfigurations(this IConfigurationBuilder builder, IServiceCollection services)
        {
            builder.Add(new DBConfigurationSource(services));

            return builder;
        }

        /// <summary>
        /// Добавляет конфигурацию в сервисы (3)
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddDallSettings(this IServiceCollection services, IConfiguration configuration)
        {
            //SettingsFromDb configuration
            var settingsFromDb = new SettingsFromDb();
            configuration.GetSection(nameof(SettingsFromDb)).Bind(settingsFromDb);
            services.AddSingleton(settingsFromDb);

            PrefixSettings.PrefixWithoutVariable = settingsFromDb.TemplatePrefixWithoutVariable;

            // Сервис - Расписание в ЕСПП. Смещение часового пояса относительно МСК для зоны ответственности рабочей группы
            services.AddSingleton<IScheduleResponseAreaTimeOffsetRepository>(provider =>
            {
                using var scope = provider.CreateScope();
                var dbContext = scope.ServiceProvider.GetRequiredService<DataContext>();
                var settingsFromDb = scope.ServiceProvider.GetRequiredService<SettingsFromDb>();
                var logger = scope.ServiceProvider.GetRequiredService<ILogger<ScheduleResponseAreaTimeOffsetRepository>>();

                return new ScheduleResponseAreaTimeOffsetRepository(dbContext, settingsFromDb, logger);
            });
        }
    }
}
