using System.Reflection;

using Microsoft.OpenApi.Models;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using WeatherForecast.Services;
using DataProviders.Extensions;
using System.Text.Json.Serialization;
using FileSecurityService.Extensions;
using ImageProvider.Extensions;
using JWTService.Extensions;
using HashService.Extensions;
using Core.Middlewares;

namespace WeatherForecast {

  /// <summary>
  /// 
  /// </summary>
  public class Startup {

    private readonly IConfiguration _configuration;

    private const string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    /// <summary>
    /// 
    /// </summary>
    /// <param name="configuration"></param>
    public Startup(IConfiguration configuration) {
      _configuration = configuration;
    }

    /// <summary>
    /// This method gets called by the runtime. Use this method to add services to the container.
    /// </summary>
    /// <param name="services"></param>
    public void ConfigureServices(IServiceCollection services) {
      string serverHostName = Environment.MachineName;

      // configure strongly typed settings objects
      var appSettingsSection = _configuration.GetSection("Configuration");
      services.Configure<Configuration>(appSettingsSection);
      var appSettings = appSettingsSection.Get<Configuration>();

   
      services.AddCors(options => {
          options.AddPolicy(MyAllowSpecificOrigins,
          builder => {
              builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
          });
      });

      services.AddControllers().AddJsonOptions(options =>
        options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull);

      #region configure jwt authentication
      if (appSettings.JwtConfig?.Secret != null) {
        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(Convert.FromBase64String(appSettings.JwtConfig.Secret)),
            ValidateIssuer = false,
            ValidateAudience = false
          };
        });
      }
      #endregion

      // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1#use-httpcontext-from-custom-components
      services.AddHttpContextAccessor();

      services.AddScoped<IContentService, ContentService>();
      services.AddScoped<IShopItemService, ShopItemService>();
      services.AddScoped<IShopItemsService, ShopItemsService>();
      services.AddScoped<IShopCartItemService, ShopCartItemService>();
      services.AddScoped<IShopCartItemsService, ShopCartItemsService>();
      services.AddScoped<IBlogItemService, BlogItemService>();
      services.AddScoped<IBlogItemsService, BlogItemsService>();
      services.AddScoped<ICategoryItemService, CategoryItemService>();
      services.AddScoped<ICategoryItemsService, CategoryItemsService>();
      services.AddScoped<IUserService, UserService>();

      services.AddScoped<IFileService, FileService>();
      services.AddScoped<IFilesService, FilesService>();
      services.AddScoped<IImageService, ImageService>();
      services.AddScoped<IPasswordService, PasswordService>();
      services.AddScoped<IAuthenticationService, AutheticationService>();

      services.RegisterDataproviders(appSettings);
      services.RegisterFileSecurityService();
      services.RegisterImageProvider();
      services.RegisterJWTService(appSettings);
      services.RegisterHashService();

      #region Swagger
      services.ConfigureSwaggerGen(options => {
        // your custom configuration goes here
        // UseFullTypeNameInSchemaIds replacement for .NET Core
        options.CustomSchemaIds(x => x.FullName);
      });

      // Register the Swagger generator, defining 1 or more Swagger documents
      services.AddSwaggerGen(config => {
        //c.SerializeAsV2 = true,
        config.SwaggerDoc("v2", new OpenApiInfo {
          Title = "MAKS-IT WEB API",
          Version = "v2",
          Description = "Site support webapi for blogs or e-commerce",

          // TermsOfService = new Uri(""),
          /*
          Contact = new OpenApiContact
          {
              Name = "",
              Email = "",
              Url = new Uri(""),
          },
          */
          License = new OpenApiLicense {
            Name = "Use under ISC",
            Url = new Uri("https://opensource.org/licenses/ISC")
          }
        });

        // Set the comments path for the Swagger JSON and UI.
        var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        config.IncludeXmlComments(xmlPath);

        // https://stackoverflow.com/questions/56234504/bearer-authentication-in-swagger-ui-when-migrating-to-swashbuckle-aspnetcore-ve
        config.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
          Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"",
          Name = "Authorization",
          In = ParameterLocation.Header,
          Type = SecuritySchemeType.ApiKey,
          Scheme = "Bearer"
        });

        config.AddSecurityRequirement(new OpenApiSecurityRequirement()
        {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            },
                            Scheme = "oauth2",
                            Name = "Bearer",
                            In = ParameterLocation.Header,

                        },
                        new List<string>()
                    }
                });

        // c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); //This line
      });
      #endregion
    }

    /// <summary>
    /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {

      if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();

        // Enable middleware to serve generated Swagger as a JSON endpoint.
        app.UseSwagger();

        // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
        // specifying the Swagger JSON endpoint.
        app.UseSwaggerUI(c => {
          c.DefaultModelsExpandDepth(-1);
          c.SwaggerEndpoint("/swagger/v2/swagger.json", "MAKS-IT WEB API v2");
          // To serve the Swagger UI at the app's root (http://localhost:<port>/), set the RoutePrefix property to an empty string
          c.RoutePrefix = "swagger";
        });
      }
      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();
      }
      //app.UseHttpsRedirection();

      app.UseRouting();

      // UseCors must be called before UseResponseCaching
      app.UseCors(MyAllowSpecificOrigins);

      // global error handler
      app.UseMiddleware<ErrorHandlerMiddleware>();

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

      app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
      });
    }
  }
}

