using System.Reflection;
using DotNetCore.CAP;
using Hotline.Api;
using Hotline.Api.Controllers;
using Hotline.Api.Controllers.Snapshot;
using Hotline.Application;
using Hotline.Application.CallCenter;
using Hotline.Application.CallCenter.Calls;
using Hotline.Application.ExportExcel;
using Hotline.Application.Jobs;
using Hotline.Application.StatisticalReport.CallReport;
using Hotline.Authentications;
using Hotline.CallCenter.Configs;
using Hotline.CallCenter.Tels;
using Hotline.Configurations;
using Hotline.DI;
using Hotline.EventBus;
using Hotline.File;
using Hotline.FlowEngine.Workflows;
using Hotline.Orders;
using Hotline.Orders.DatabaseEventHandler;
using Hotline.Repository.SqlSugar;
using Hotline.Repository.SqlSugar.DataPermissions;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Repository.SqlSugar.Ts;
using Hotline.Settings.TimeLimitDomain;
using Hotline.Settings.TimeLimitDomain.ExpireTimeSupplier;
using Hotline.Tests.Mock;
using Hotline.Tests.Mock.Interfaces;
using Hotline.Tests.SqlSuger;
using Mapster;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Senparc.Weixin.AspNet;
using Senparc.Weixin.RegisterServices;
using TianQue.Sdk;
using Tr.Sdk;
using XF.Domain.Authentications;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Options;
using XF.Domain.Repository;
using XF.Domain.Repository.Events;
using XF.EasyCaching;
using XF.Utility.MQ;
using Xunit.DependencyInjection.AspNetCoreTesting;
using Hotline.Pdf;
using Hotline.ThirdAccountDomainServices.Interfaces;
using Hotline.Snapshot.IRepository;
using Hotline.WeChat;
using Hotline.Tests.Controller;

namespace Hotline.Tests;
public class Startup
{
    private const string JsonFile = "appsettings.Development.json";
    public void ConfigureHost(IHostBuilder hostBuilder)
    {
        //hostBuilder
        //.ConfigureHostConfiguration(builder =>
        //{
        //    builder.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
        //    .AddEnvironmentVariables();
        //});
        hostBuilder
            .ConfigureWebHost(webHostBuilder => webHostBuilder
            .UseTestServerAndAddDefaultHttpClient()
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile(JsonFile, optional: true, reloadOnChange: true);
            })
            .UseStartup<AspNetCoreStartup>());
    }

    private class AspNetCoreStartup
    {
        public AspNetCoreStartup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
            var configuration = Configuration;
            var appConfigurationSection = configuration.GetRequiredSection(nameof(AppConfiguration));
            var appConfiguration = appConfigurationSection.Get<AppConfiguration>();
            if (appConfiguration is null) throw new ArgumentNullException(nameof(appConfiguration));

            var callCenterConfigurationSection = configuration.GetRequiredSection(nameof(CallCenterConfiguration));
            var callCenterConfiguration = callCenterConfigurationSection.Get<CallCenterConfiguration>();

            services.Configure<AppConfiguration>(d => appConfigurationSection.Bind(d));
            services.Configure<IdentityConfiguration>(d => configuration.GetSection(nameof(IdentityConfiguration)).Bind(d));
            services.Configure<CityBaseConfiguration>(d => configuration.GetSection(nameof(CityBaseConfiguration)).Bind(d));
            services.AddScoped<IOptionsSnapshot<AppConfiguration>, OptionsSnapshotMock>();

            services.RegisterMapper();
            //services.AddControllers()
            //    .AddControllersAsServices();

            //sqlsugar
            services.AddSqlSugar(configuration);
            services.AddCAPDb(configuration);


            //mq
            services.AddTestMq(configuration);

            services.AddPdfManager();

            services.AddScoped<IDataPermissionFilterBuilder, DataPermissionFilterBuilder>();
            services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));
            //services.AddScoped<IHttpContextAccessor, DefaultHttpContextAccessor>();
            services.AddCache(d =>
            {
                var cacheConfig = configuration.GetSection("Cache").Get<CacheOptions>();
                cacheConfig.Adapt(d);
                d.Prefix = "Hotline";
                d.TopicName = "hotline-topic";
            });
            services.AddScoped(typeof(IPasswordHasher<>), typeof(PasswordHasher<>));
            services.AddScoped(typeof(ITypedCache<>), typeof(DefaultTypedCache<>));
            services.AddScoped(typeof(IRepositoryTextSearch<>), typeof(BaseRepositoryTextSearch<>));
            services.AddScoped<ICallApplication, TianRunCallApplication>();
            services.AddScoped<ITrApplication, TrApplication>();
            services.AddTrSdk(callCenterConfiguration.TianRun.Address,
                        callCenterConfiguration.TianRun.Username,
                        callCenterConfiguration.TianRun.Password);
            services.RegisterMediatR(appConfiguration);
            services.RegisterSignalR(configuration);

            services.AddSenparcWeixinServices(configuration);
            AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(d => d.GetTypes())
                .Where(d => d.GetInterfaces().Any(x =>
                    x == typeof(IScopeDependency)
                    || x == typeof(ISingletonDependency)
                    || x == typeof(ITransientDependency))
                            && d.GetInterfaces().All(x => x != typeof(IIgnoreDependency)))
                .ToList()
                .ForEach(d => ServiceRegister.Register(services, d));

            //services.AddScoped<IThirdIdentiyService, WeChatService>();
            services.AddScoped<IThirdIdentiyService, ThirdTestService>();

            services.AddScoped<IUpdateDatabaseEvent<OrderVisitDetail>, OrderVisitDetailEventHandler>();
            services.AddWeChatService(configuration);

            //services.AddScoped<IThirdAccountRepository, ThirdAccountRepository>();
            services.AddApplication();
            services.AddScoped<IOrderServiceStartWorkflow, OrderServiceStartWorkflow>();
            services.AddScoped<IExpireTimeSupplier, DaySupplier>();
            services.AddScoped<IExpireTimeSupplier, WorkDaySupplier>();
            services.AddScoped<IExpireTimeSupplier, HourSupplier>();
            services.AddScoped<ExpireTimeFactory>();
            services.AddScoped<YiBinExpireTimeLimit>();
            services.AddScoped<ZiGongExpireTimeLimit>();
            services.AddScoped<LuZhouExpireTimeLimit>();
            services.AddScoped<ZiGongCallReportApplication>();
            services.AddScoped<YiBinCallReportApplication>();
            services.AddScoped<IMediator, MediatorMock>();
            services.AddScoped<IExportApplication, ExportApplication>();
            services.AddScoped<OrderController>();
            services.AddScoped<IndustryController>();
            services.AddScoped<UserController>();
            services.AddScoped<SnapshotController>();
            services.AddScoped<KnowledgeController>();
            services.AddScoped<RedPackController>();
            services.AddScoped<PushMessageController>();
            services.AddHttpContextAccessor();
            services.AddScoped<ISessionContext, Controller.TestSessionContext>();
            services.AddScoped<ISessionContextManager, TestSessionContextManager>();
            services.AddScoped<ISessionContextProvider, SessionContextProvider>();
            services.AddScoped<ICallApplication, XingTangCallApplication>();
            services.AddScoped<XingTangCallApplication>();
            services.AddScoped<OrderServiceMock>();
            services.AddScoped<KnowledgeServiceMock>();
            services.AddXingTangDb(callCenterConfiguration.XingTang);
            services.AddScoped<XingTangCallsSyncJob>();
            services.AddScoped<XingTangCallSatisfactionSyncJob>();
            services.AddScoped<IFileDomainService, FileDomainService>();
            services.AddScoped<IGuiderSystemService, TiqnQueService>();
            services.AddScoped<IWorkflowDomainService, WorkflowDomainService>();
            services.AddScoped<ICallTelClient,XingTang.CallTelClient>();

            //ServiceLocator.Instance = services.BuildServiceProvider();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseSenparcWeixin(env, null, null, register => { }, (register, weixinSetting) => { });
        }
    }
}

public static class StartupHelper
{
    public static IServiceCollection RegisterMediatR(this IServiceCollection services, AppConfiguration appConfiguration)
    {
        services.AddScoped<Publisher>();
        services.AddMediatR(cfg =>
        {
            cfg.TypeEvaluator = d =>
            {
                var attr = d.GetCustomAttribute(typeof(InjectionAttribute)) as InjectionAttribute;
                if (attr is null) return true;
                return attr.IsEnable(appConfiguration.AppScope,
                    appConfiguration.GetDefaultAppScopeConfiguration().CallCenterType);
            };
            cfg.RegisterServicesFromAssembly(typeof(ApplicationStartupExtensions).Assembly);
        });

        return services;
    }

    /// <summary>
    /// SignalR
    /// </summary>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <returns></returns>
    public static IServiceCollection RegisterSignalR(this IServiceCollection services, IConfiguration configuration)
    {
        var cacheConfig = configuration.GetRequiredSection("Cache").Get<CacheOptions>();
        services.AddSignalR().AddStackExchangeRedis($"{cacheConfig.Host}:{cacheConfig.Port}", options =>
        {
            options.Configuration.ChannelPrefix = "Hotline:signalr:";
            options.Configuration.Password = cacheConfig.Password;
            options.Configuration.DefaultDatabase = cacheConfig.Database;
        });
        return services;
    }

    public static IServiceCollection AddTestMq(this IServiceCollection services, IConfiguration configuration)
    {
        MqConfiguration mqConfiguration = configuration.GetSection("MqConfiguration").Get<MqConfiguration>();
        services.AddCap(delegate (CapOptions x)
        {
            if (!(mqConfiguration.DbType == "PostgreSql"))
            {
                throw new ArgumentOutOfRangeException();
            }

            x.UsePostgreSql(mqConfiguration.DbConnectionString);
            if (!(mqConfiguration.MqType == "RabbitMq"))
            {
                throw new ArgumentOutOfRangeException();
            }

            RabbitMq rabbitmq = mqConfiguration.RabbitMq;
            if (rabbitmq == null)
            {
                throw new ArgumentNullException("未配置RabbitMq参数");
            }

            x.UseRabbitMQ(delegate (RabbitMQOptions d)
            {
                d.UserName = rabbitmq.UserName;
                d.Password = rabbitmq.Password;
                d.HostName = rabbitmq.HostName;
                d.Port = rabbitmq.Port;
                d.VirtualHost = rabbitmq.VirtualHost;
            });

            if (!string.IsNullOrEmpty(mqConfiguration.DefaultGroup))
            {
                x.DefaultGroupName = mqConfiguration.DefaultGroup;
            }

            if (!string.IsNullOrEmpty(mqConfiguration.TopicNamePrefix))
            {
                x.TopicNamePrefix = mqConfiguration.TopicNamePrefix;
            }
        });
        return services;
    }
}
