using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using AutoMapper;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.IdentityModel.Tokens;
using OnlineAssessment.Common;
using OnlineAssessment.Data;
using OnlineAssessment.Data.EFCore;
using Swashbuckle.AspNetCore.SwaggerGen;
using FirebaseAdmin;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Razorpay.Api;

namespace OnlineAssessment
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            //Getting Response Messages From Config File (appresponsemessages.json)
            dynamic builder;
            if (env.EnvironmentName.Equals("Development"))
            {
                builder = new ConfigurationBuilder()
                  .SetBasePath(env.ContentRootPath)
                  .AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
                  .AddJsonFile("appresponsemessages.json", optional: false, reloadOnChange: true)
                  .AddEnvironmentVariables();
            }
            else
            {
                builder = new ConfigurationBuilder()
                  .SetBasePath(env.ContentRootPath)
                  .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                  .AddJsonFile("appresponsemessages.json", optional: false, reloadOnChange: true)
                  .AddEnvironmentVariables();
            }
            configuration = builder.Build();
            Configuration = configuration;
        }


        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            /*
            app.UseStaticFiles();
            app.UseStaticFiles(new StaticFileOptions()
            {
                FileProvider = new PhysicalFileProvider(
                Path.Combine(Directory.GetCurrentDirectory(), "Content")),
                RequestPath = "/Content"
            });
            */

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

            // Enable middleware to serve swagger-ui  
            app.UseSwaggerUI(
                options =>
                {
                    options.InjectStylesheet("/Content/custom.css");
                    // build a swagger endpoint for each discovered API version
                    foreach (var description in provider.ApiVersionDescriptions)
                    {
                        options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
                    }
                });

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

            app.UseCors();

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseMiddleware(typeof(ErrorHandlingMiddleware));

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


        public void ConfigureServices(IServiceCollection services)
        {
            //Firebase
            FirebaseApp.Create(new AppOptions
            {
                Credential = GoogleCredential.FromFile(@"Firebase//practice-kea-7cb5b-firebase-adminsdk-e4h19-6e05200a3f.json")
            });

            RazorpayClient client = new RazorpayClient("rzp_test_T9n4ai2HS10jMs", "nApJhqrFery11ebXaGWSDoeO");

            services.AddAutoMapper(typeof(AutoMapping));
            services.AddDbConnections(Configuration);

            //

            services
                .AddScoped<EfCoreCommonRepository>()
                .AddScoped<EFCoreUserGroupRepository>()
                .AddScoped<EfCoreUserRepository>()
                .AddScoped<EFCoreExamAttemptRepository>()
                .AddScoped<EFCorePracticeAttemptRepository>();

            //

            services.AddCors(o => o.AddPolicy("OdiwarePolicy", builder =>
            {
                builder
                       .AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader()
                       //.AllowCredentials()
                       .Build();
            }));

            //

            //Firebase
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.Authority = "https://securetoken.google.com/practice-kea-7cb5b";
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidIssuer = "https://securetoken.google.com/practice-kea-7cb5b",
                        ValidateAudience = true,
                        ValidAudience = "practice-kea-7cb5b",
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true
                    };
                });
            
            /*
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        //ValidIssuer = Configuration["Jwt:Issuer"],
                        //ValidAudience = Configuration["Jwt:Issuer"],
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
                    };
                });
            */
            //

            services.AddControllers()
               .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>())
               .AddNewtonsoftJson(option => option.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

            //

            services.AddApiVersioning(
                options =>
                {
                    // reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
                    //options.ReportApiVersions = true;

                    // Specify the default API Version as 1.0
                    options.DefaultApiVersion = new ApiVersion(1, 0);

                    // If the client hasn't specified the API version in the request, use the default API version number 
                    options.AssumeDefaultVersionWhenUnspecified = true;

                    // Advertise the API versions supported for the particular endpoint
                    // Reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
                    options.ReportApiVersions = true;

                    // Supporting multiple versioning scheme
                    //config.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("X-version"), new QueryStringApiVersionReader("api-version"));
                    options.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("X-version"));
                });

            //

            services.AddVersionedApiExplorer(
                options =>
                {
                    // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
                    // note: the specified format code will format the version as "'v'major[.minor][-status]"
                    options.GroupNameFormat = "'v'VVV";

                    // note: this option is only necessary when versioning by url segment. the SubstitutionFormat
                    // can also be used to control the format of the API version in route templates
                    options.SubstituteApiVersionInUrl = true;
                });

            //

            services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerConfigureOptions>();
            services.AddSwaggerGen(
                options =>
                {
                    // add a custom operation filter which sets default values
                    options.OperationFilter<SwaggerDefaultValues>();

                    // integrate xml comments
                    options.IncludeXmlComments(XmlCommentsFilePath);
                });


            //

            services.AddSingleton(Configuration.GetSection("ResponseMessage").Get<ResponseMessage>());
            services.Configure<ResponseMessage>((setting) =>
            {
                Configuration.GetSection("ResponseMessage").Bind(setting);
            });
            services.Configure<ApiBehaviorOptions>(a => a.InvalidModelStateResponseFactory = actionContext =>
             {
                 return new BadRequestObjectResult(new
                     ReturnResponse(string.Empty,
                     new ReturnStatus(
                         "-1",
                         actionContext.ModelState.Values.SelectMany(x => x.Errors)
                         .Select(x => x.ErrorMessage)
                     )
                     ));
             });
        }
        static string XmlCommentsFilePath
        {
            get
            {
                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml";
                return Path.Combine(basePath, fileName);
            }
        }
    }

}
