using DiplomovaPrace.DependencyInjection;
using DiplomovaPrace.Facades.Addresses;
using DiplomovaPrace.Facades.DeliveryTypes;
using DiplomovaPrace.Facades.Infrastructure;
using DiplomovaPrace.Facades.Orders;
using DiplomovaPrace.Facades.OrderStates;
using DiplomovaPrace.Facades.PaymentStates;
using DiplomovaPrace.Facades.PaymentTypes;
using DiplomovaPrace.Facades.ProductCategories;
using DiplomovaPrace.Facades.Products;
using DiplomovaPrace.Services.Infrastructure;
using DiplomovaPrace.Services.Mailer;
using DiplomovaPrace.Services.Security;
using DiplomovaPrace.Web.Server.Infrastructure.ConfigurationExtensions;
using DiplomovaPrace.Web.Server.Infrastructure.Cors;
using DiplomovaPrace.Web.Server.Infrastructure.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using ProtoBuf.Grpc.Server;

namespace DiplomovaPrace.Web.Server
{
	public class Startup
	{
		public readonly IConfiguration configuration;

		public Startup(IConfiguration configuration)
		{
			this.configuration = configuration;
		}

		// This method gets called by the runtime. Use this method to add services to the container.
		// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
		public void ConfigureServices(IServiceCollection services)
		{
			services.AddOptions();
			services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
			services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
			services.AddCustomizedAuthentication(configuration);
			services.AddAuthorization(options => options.DefaultPolicy = new AuthorizationPolicyBuilder(AuthenticationConfig.GetAuthenticationSchemes(configuration))
				   .RequireAuthenticatedUser()
				   .Build());

			services.AddCustomizedMvc(configuration);

			services.ConfigureForWebServer(configuration);

			services.AddCodeFirstGrpc(config =>
			{
				config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal;
				config.MaxReceiveMessageSize = null; //unlimited grpc recieve message
			});

			services.AddCustomizedCors(configuration);

			// maximum size of messgae (productImage)
			services.AddServerSideBlazor().AddHubOptions(o =>
			{
				o.MaximumReceiveMessageSize = 10 * 1024 * 1024; // 10MB
			});

			// server-side UI
			services.AddControllersWithViews();
			services.AddRazorPages();

			services.Configure<ProductImageStorage>(configuration.GetSection("AppSettings:ProductImageStorage"));
			services.Configure<UrlConfiguration>(configuration.GetSection("AppSettings:UrlConfiguration"));
			services.Configure<MailerConfiguration>(configuration.GetSection("AppSettings:MailerConfiguration"));
			services.Configure<AesConfiguration>(configuration.GetSection("AppSettings:AesConfiguration"));
		}

		// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
		public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions<CorsOptions> corsOptions)
		{
			if (env.IsDevelopment())
			{
				app.UseDeveloperExceptionPage();
				app.UseWebAssemblyDebugging();
			}
			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.UseBlazorFrameworkFiles();
			app.UseStaticFiles();

			app.UseRouting();

			app.UseGrpcWeb(new GrpcWebOptions() { DefaultEnabled = true });

			app.UseCustomizedCors(corsOptions);

			app.UseBlazorFrameworkFiles();
			app.UseStaticFiles();

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

			app.UseEndpoints(endpoints =>
			{
				endpoints.MapRazorPages();
				endpoints.MapControllers();
				endpoints.MapFallbackToFile("index.html");

				endpoints.MapGrpcService<AddressFacade>();
				endpoints.MapGrpcService<DeliveryTypeFacade>();
				endpoints.MapGrpcService<OrderFacade>();
				endpoints.MapGrpcService<OrderStateFacade>();
				endpoints.MapGrpcService<PaymentStateFacade>();
				endpoints.MapGrpcService<PaymentTypeFacade>();
				endpoints.MapGrpcService<ProductFacade>();
				endpoints.MapGrpcService<ProductCategoryFacade>();
				endpoints.MapGrpcService<SecurityService>();
			});

			app.UseCustomizedMvc();

			app.UpgradeDatabaseSchemaAndData();
		}
	}
}
