using HRM.BO;
using HRM.DA;
using HRM.UI.Configuration.DI;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
using System.ComponentModel.DataAnnotations;
using System.Text;
using HRM.BO.Configuration;

namespace HRM.UI.Api
{
    public class Startup
    {
        public IWebHostEnvironment HostingEnvironment { get; private set; }

        private readonly ILogger _logger;
        private readonly AppSettings _appSettings;
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration, IWebHostEnvironment env, ILogger<Startup> logger)
        {
            _logger = logger;
            HostingEnvironment = env;
            Configuration = configuration;

            _appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>();
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddControllersWithViews();
            //services.AddSpaStaticFiles(configuration =>
            //{
            //    configuration.RootPath = "ClientApp/dist";
            //});
            _logger.LogTrace("Startup::ConfigureServices");
            services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
            services.Configure<EmployeeApiInfo>(Configuration.GetSection("EmployeeApiInfo"));
            services.Configure<AdminPendingJob>(Configuration.GetSection("AdminPendingJob"));
            services.Configure<MobileAppSettings>(Configuration.GetSection("MobileAppSettings"));
            services.Configure<FundInfo>(Configuration.GetSection("FundInfo"));

            try
            {
                if (AppSettings.IsValid())
                {
                    #region Dependency injection with services

                    services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

                    #endregion

                    _logger.LogDebug("Startup::ConfigureServices::valid AppSettings");

                    #region App settings

                    services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

                    #endregion

                    #region Controllers

                    services.AddHttpClient<ApiIntegrationService>();

                    services.AddControllers(
                            options => { options.Filters.Add(new ProducesAttribute("application/json")); })
                        .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
                    services.AddControllers().AddNewtonsoftJson();

                    services.AddControllersWithViews(options => { options.AllowEmptyInputInBodyModelBinding = true; });

                    #endregion

                    #region API versioning

                    services.AddApiVersioning(
                        options =>
                        {
                            options.ReportApiVersions = true;
                            options.DefaultApiVersion = new ApiVersion(1, 0);
                            options.AssumeDefaultVersionWhenUnspecified = true;
                            options.ApiVersionReader = new UrlSegmentApiVersionReader();
                        });

                    #endregion

                    #region CORS

                    services.AddCors(options =>
                    {
                        options.DefaultPolicyName = "CORSPolicy";
                        options.AddDefaultPolicy(
                            builder =>
                            {
                                //builder.WithOrigins("http://localhost:4200")
                                //.SetIsOriginAllowedToAllowWildcardSubdomains();
                                //builder.AllowAnyMethod();
                                //builder.AllowAnyHeader();
                                //builder.AllowCredentials();
                                builder.WithOrigins("http://localhost:4200")
                                    .SetIsOriginAllowedToAllowWildcardSubdomains();
                                builder.AllowAnyMethod();
                                builder.AllowAnyHeader();
                                builder.AllowCredentials();
                            });
                    });

                    #endregion

                    #region Versioned Api Explorer

                    //Format the version as "'v'major[.minor][-status]"
                    services.AddVersionedApiExplorer(
                        options =>
                        {
                            options.GroupNameFormat = "'v'VVV";
                            options.SubstituteApiVersionInUrl = true;
                        });

                    #endregion

                    #region Session

                    services.AddDistributedMemoryCache();
                    services.AddSession(
                        options => { options.IdleTimeout = TimeSpan.FromMinutes(60); });

                    #endregion

                    #region JWT Authentication

                    var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
                    services.AddAuthentication(
                            options =>
                            {
                                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                            })
                        .AddJwtBearer(options =>
                        {
                            options.RequireHttpsMetadata = false;
                            options.SaveToken = true;
                            options.TokenValidationParameters = new TokenValidationParameters
                            {
                                ValidateIssuerSigningKey = true,
                                IssuerSigningKey = new SymmetricSecurityKey(key),
                                ValidateIssuer = false,
                                ValidateAudience = false
                            };
                        });

                    #endregion

                    #region Antiforgery

                    services.AddMvc();
                    services.AddAntiforgery(options => { options.HeaderName = "Ease.HR.X-XSRF-TOKEN"; });

                    #endregion

                    //#region Auto Mapper Configurations

                    //var mappingConfig = new MapperConfiguration(mc =>
                    //{
                    //    mc.AddProfile(new APIMappingProfile());
                    //});

                    //IMapper mapper = mappingConfig.CreateMapper();
                    //services.AddSingleton(mapper);

                    //#endregion

                    //#region SWAGGER

                    //if (_appSettings.Swagger.Enabled)
                    //{
                    //    services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
                    //    services.AddSwaggerGen(options =>
                    //    {
                    //        options.OperationFilter<SwaggerDefaultValues>();
                    //        options.IncludeXmlComments(XmlCommentsFilePath);
                    //    });
                    //}

                    //#endregion

                    # region Mappings

                    services.ConfigureMappings();

                    #endregion

                    #region Business Service

                    services.ConfigureBusinessServices(Configuration);

                    #endregion

                    _logger.LogDebug("Startup::ConfigureServices::ApiVersioning, Swagger and DI settings");
                }
                else
                {
                    _logger.LogDebug("Startup::ConfigureServices::invalid AppSettings");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
            }
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            #region CORS

            app.UseCors("CORSPolicy");

            #endregion

            app.UseHttpsRedirection();
            //app.UseDefaultFiles();
            app.UseStaticFiles();
            //if (!env.IsDevelopment())
            //{
            //    app.UseSpaStaticFiles();
            //}

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseSession();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }
    }

    public class AppSettings
    {
        [Required] public string DefaultDB { get; set; }
        public string Secret { get; set; }
        public string DownloadFolder { get; set; }

        [Required] public ApiSettings API { get; set; }
        //       [Required]
        //public Swagger Swagger { get; set; }
        //[Required]

        public static bool IsValid()
        {
            return true;
        }
        public string RDLCLocation { get; set; }
        //public static bool IsValid<T>(this T data)
        //{
        //    if (data == null)
        //        throw new ArgumentNullException(nameof(data));

        //    var validationResult = new List<ValidationResult>();
        //    var result = Validator.TryValidateObject(data, new System.ComponentModel.DataAnnotations.ValidationContext(data), validationResult, false);

        //    if (!result)
        //    {
        //        foreach (var item in validationResult)
        //        {
        //            Debug.WriteLine($"ERROR::{item.MemberNames}:{item.ErrorMessage}");
        //        }
        //    }

        //    return result;
        //}
    }


    public class ApiSettings
    {
        [Required] public string Title { get; set; }

        public string Description { get; set; }

        public ApiContact Contact { get; set; }

        public string TermsOfServiceUrl { get; set; }

        public ApiLicense License { get; set; }
    }

    public class ApiContact
    {
        public string Name { get; set; }
        public string Email { get; set; }

        public string Url { get; set; }
    }

    public class ApiLicense
    {
        public string Name { get; set; }
        public string Url { get; set; }
    }
}