using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using ReallifeGamemode.Database.Models;
using ReallifeGamemode.DataService.Logic;
using Swashbuckle.AspNetCore.Swagger;


namespace ReallifeGamemode.DataService
{
  public class Startup
  {
    private readonly ILogger<Startup> logger;
    private readonly IConfiguration configuration;
    private readonly IWebHostEnvironment environment;

    public Startup(IConfiguration configuration,IWebHostEnvironment environment, ILogger<Startup> logger)
    {
      this.configuration = configuration;
      this.environment = environment;
      this.logger = logger;
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
      services.Configure<ServerConfig>(cfg => configuration.Bind(cfg));

      services.AddDbContext<DatabaseContext>();

      services.AddCors();

      services.AddLogic();

      services
        .AddMvc()
        .AddNewtonsoftJson(j =>
      {
        j.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
        j.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        j.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat;
      });

      var tokenKey = Encoding.ASCII.GetBytes(configuration["TokenSecret"]);
      services.AddAuthentication(o =>
      {
        o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
      })
      .AddJwtBearer(o =>
      {
        o.IncludeErrorDetails = this.environment.IsDevelopment();
        o.RequireHttpsMetadata = this.environment.IsProduction();
        o.SaveToken = false;
        o.TokenValidationParameters = new TokenValidationParameters
        {
          ValidateIssuerSigningKey = true,
          IssuerSigningKey = new SymmetricSecurityKey(tokenKey),
          ValidateIssuer = false,
          ValidateAudience = false
        };
      });

      string debugToken = null;

#if DEBUG
#pragma warning disable ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
      debugToken = services.BuildServiceProvider().GetService<JwtTokenGenerator>().GetDebugToken(tokenKey);
#pragma warning restore ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
#endif

      services.AddSwaggerGen(c =>
      {
        OpenApiInfo info = new OpenApiInfo
        {
          Title = "GTA:V ControlPanl DataService",
          Version = "0.1",
        };

        if (debugToken != null)
        {
          info.Description = $"Debug-Token: {debugToken}";
        }

        c.SwaggerDoc("DataService", info);

        c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
        {
          Name = "Authorization",
          In = ParameterLocation.Header,
          Type = SecuritySchemeType.ApiKey,
          Scheme = "Bearer"
        });

        c.AddSecurityRequirement(new OpenApiSecurityRequirement()
        {
          {
            new OpenApiSecurityScheme()
            {
              Reference = new OpenApiReference
              {
                Type = ReferenceType.SecurityScheme,
                Id = "Bearer"
              }
            },
            new string[] {}
          }
        });
      });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
    {
      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }

      app.UseRouting();

      app.UseAuthentication();

      app.UseStaticFiles();

      app.UseCors(c =>
      {
        c.AllowAnyOrigin()
         .AllowAnyMethod()
         .AllowAnyHeader();
      });

      app.UseSwaggerUI(c =>
      {
        c.RoutePrefix = "doc";
        c.SwaggerEndpoint("DataService.json", "DataService");
      });

      app.UseSwagger(c =>
      {
        c.RouteTemplate = "doc/{documentName}.json";
      });

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