using FrontendWebApi.Jwt;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Repository.BackendRepository.Implement;
using Repository.BackendRepository.Interface;
using Repository.BaseRepository.Implement;
using Repository.BaseRepository.Interface;
using Repository.FrontendRepository.Implement;
using Repository.FrontendRepository.Interface;
using Repository.Models;
using Repository.Services.Implement;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FrontendWebApi.Jwt.JwtHelpers;

namespace FrontendWebApi
{
    public class Startup
    {
        public DBConfig dBConfig = new DBConfig()
        {
            MSSqlDBConfig = new MSSqlDBConfig(),
            MySqlDBConfig = new MySqlDBConfig()
        };

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;

            dBConfig.MSSqlDBConfig.Server = Configuration.GetValue<string>("DBConfig:MSSqlDBConfig:Server");
            dBConfig.MSSqlDBConfig.Port = Configuration.GetValue<string>("DBConfig:MSSqlDBConfig:Port");
            dBConfig.MSSqlDBConfig.Root = Configuration.GetValue<string>("DBConfig:MSSqlDBConfig:Root");
            dBConfig.MSSqlDBConfig.Password = Configuration.GetValue<string>("DBConfig:MSSqlDBConfig:Password");
            dBConfig.MSSqlDBConfig.Database = Configuration.GetValue<string>("DBConfig:MSSqlDBConfig:Database");

            dBConfig.MySqlDBConfig.Server = Configuration.GetValue<string>("DBConfig:MySqlDBConfig:Server");
            dBConfig.MySqlDBConfig.Port = Configuration.GetValue<string>("DBConfig:MySqlDBConfig:Port");
            dBConfig.MySqlDBConfig.Root = Configuration.GetValue<string>("DBConfig:MySqlDBConfig:Root");
            dBConfig.MySqlDBConfig.Password = Configuration.GetValue<string>("DBConfig:MySqlDBConfig:Password");
            dBConfig.MySqlDBConfig.Database = Configuration.GetValue<string>("DBConfig:MySqlDBConfig:Database");
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<JwtHelpers>();
            services.AddControllersWithViews();
            //services.AddControllers();

            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy", policy =>
                {
                    policy.AllowAnyOrigin()
                          .AllowAnyHeader()
                          .AllowAnyMethod();
                });
            });
            services.AddLogging(
            builder =>
            {
                builder.AddFilter("Microsoft", LogLevel.Warning)
                       .AddFilter("System", LogLevel.Warning)
                       .AddFilter("NToastNotify", LogLevel.Warning)
                       .AddConsole();
            });

            #region DBHelper �`�J
            services.Configure<DBConfig>(Configuration.GetSection("DBConfig"));
            services.AddTransient<Repository.Helper.IDatabaseHelper, Repository.Helper.DatabaseHelper>();
            #endregion DBHelper �`�J

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

            #region Repository �`�J
            services.AddTransient<IBackendRepository, BackendRepository>();
            services.AddTransient<IFrontendRepository, FrontendRepository>();
            services.AddTransient<IBaseRepository, BaseRepository>();
            #endregion Repository �`�J

            #region JWT �`�J
            services.AddTransient<IJwtHelpers, JwtHelpers>();
            //services.AddSingleton<JwtHelpers>();
            services
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    // �����ҥ��ѮɡA�^�����Y�|�]�t WWW-Authenticate ���Y�A�o�̷|��ܥ��Ѫ��Բӿ��~��]
                    options.IncludeErrorDetails = true; // �w�]�Ȭ� true�A���ɷ|�S�O����

                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        // �z�L�o���ŧi�A�N�i�H�q "sub" ���Ȩó]�w�� User.Identity.Name
                        NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
                        // �z�L�o���ŧi�A�N�i�H�q "roles" ���ȡA�åi�� [Authorize] �P�_����
                        RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",

                        // �@��ڭ̳��|���� Issuer
                        ValidateIssuer = true,
                        ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"),
                        RequireExpirationTime = true,
                        // �q�`���ӻݭn���� Audience
                        ValidateAudience = false,
                        //ValidAudience = "JwtAuthDemo", // �����ҴN���ݭn��g

                        // �@��ڭ̳��|���� Token �����Ĵ���
                        ValidateLifetime = true,

                        // �p�G Token ���]�t key �~�ݭn���ҡA�@�볣�u��ñ���Ӥw
                        ValidateIssuerSigningKey = false,

                        // "1234567890123456" ���ӱq IConfiguration ���o
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey")))
                    };
                });
            #endregion JWT �`�J

            double loginExpireMinute = this.Configuration.GetValue<double>("LoginExpireMinute");
            services.AddSession(options =>
            {
                options.Cookie.Name = "WebApi.Session";
                options.IdleTimeout = TimeSpan.FromMinutes(loginExpireMinute);
            });
        }

        // 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)
        {
            loggerFactory.AddFile("Logs/log-{Date}.txt");

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/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.UseSession();
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            //IdentityModelEventSource.ShowPII = true;
            app.UseRouting();
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            app.UseCors(x => x
                .AllowAnyMethod()
                .AllowAnyHeader()
                .SetIsOriginAllowed(origin => true) // allow any origin
                .AllowCredentials());
            app.UseAuthentication();
            app.UseAuthorization();


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

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