using Autofac;
using Insight.Database;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Npgsql;
using PlanTempus.Database.ConfigurationManagementSystem;
using PlanTempus.Database.Core.DCL;
using PlanTempus.Database.Core.DDL;
using System.Data;
using System.Diagnostics;
using PlanTempus.Core.Database.ConnectionFactory;

namespace PlanTempus.SetupInfrastructure
{
    /// <summary>
    /// SETUP APPLICATION USER NAMED sathumper
    /// 
    /// This should be handled on the Postgresql db server with a superadmin or similar.
    /// 
    /// Execute SQL CreateRole.txt
    /// 
    /// After that is executed it is time for running this main program
    /// Remember to use the newly created sathumper
    /// "ConnectionStrings": {
    ///  "DefaultConnection": "Host=192.168.1.57;Port=5432;Database=ptdb01;User Id=[uid];Password=[secret];"
    /// </summary>
    internal class Program
    {
        static async Task Main(string[] args)
        {
            try
            {
                var host = Host.CreateDefaultBuilder(args)
                    .UseEnvironment("Dev")
                    .UseServiceProviderFactory(
                        new Autofac.Extensions.DependencyInjection.AutofacServiceProviderFactory())
                    .ConfigureContainer<ContainerBuilder>((hostContext, builder) =>
                    {
                        var startup = new Startup();
                        startup.ConfigureContainer(builder);
                    })
                    .Build();

                await host.StartAsync();
                Console.WriteLine("Host has started.");


                var console = host.Services.GetRequiredService<ConsoleService>();
                console.Run();

                await host.WaitForShutdownAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Host failed to start: {ex}");
            }
        }
    }

    public class ConsoleService(
        IDbConnectionFactory connectionFactory,
        SetupDbAdmin setupDbAdmin,
        SetupIdentitySystem setupIdentitySystem,
        SetupConfiguration setupConfiguration,
        SetupApplicationUser setupApplicationUser,
        SetupOutbox setupOutbox)
    {
        static ConsoleColor _backgroundColor = Console.BackgroundColor;
        static ConsoleColor _foregroundColor = Console.ForegroundColor;

        bool IsSuperAdmin(ConnectionStringParameters parameters)
        {
            Console.WriteLine("Testing db access...");

            string query = @"SELECT usename, usesuper FROM pg_user WHERE usename = CURRENT_USER;";

            using var conn = connectionFactory.Create(parameters);
            var result = (dynamic)conn.QuerySql(query).Single();

            string username = result.usename;
            bool isSuperuser = (bool)result.usesuper;

            if ((bool)result.usesuper)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine();
                Console.BackgroundColor = ConsoleColor.Yellow;
                Console.WriteLine("TEST SUCCESSFULLY");
                Console.ForegroundColor = ConsoleColor.White;
                Console.BackgroundColor = ConsoleColor.Black;
                Console.WriteLine();
                Console.WriteLine("-------------------------------");
                Console.WriteLine();
                Console.WriteLine($"Username: {username}");
                Console.WriteLine($"Super admin: true");
                Console.WriteLine();
                Console.WriteLine("-------------------------------");


                Console.WriteLine("Press any key to start database setup");
                Console.Read();

                return true;
            }


            Console.ForegroundColor = ConsoleColor.Green;
            Console.BackgroundColor = ConsoleColor.Red;
            Console.WriteLine();
            Console.WriteLine("TEST WAS NOT SUCCESSFULLY");
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.White;
            Console.BackgroundColor = ConsoleColor.Black;
            Console.WriteLine("-------------------------------");
            Console.WriteLine();
            Console.WriteLine($"Username: {username}");
            Console.WriteLine($"Super admin: false");
            Console.WriteLine();
            Console.WriteLine("-------------------------------");


            Console.WriteLine("User is required to be super admin");
            Console.Read();

            return false;
        }

        static void Welcome()
        {
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.WriteLine(@"__________.__              ___________                                 
\______   \  | _____    ___\__    ___/___   _____ ______  __ __  ______
 |     ___/  | \__  \  /    \|    |_/ __ \ /     \\____ \|  |  \/  ___/
 |    |   |  |__/ __ \|   |  \    |\  ___/|  Y Y  \  |_> >  |  /\___ \ 
 |____|   |____(____  /___|  /____| \___  >__|_|  /   __/|____//____  >
                    \/     \/           \/      \/|__|              \/ 
            _________       __                                         
           /   _____/ _____/  |_ __ ________                          
           \_____  \_/ __ \   __\  |  \____ \                        
           /        \  ___/|  | |  |  /  |_> >                       
          /_______  /\___  >__| |____/|   __/                        
                  \/     \/           |__|");
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.White;
        }

        public void Run()
        {
            Welcome();
            string userPass;

            try
            {
                do
                {
                    Console.WriteLine("Input username:password for a superadmin role");
                    userPass = Console.ReadLine() ?? string.Empty;
                } while (!userPass.Contains(':') || userPass.Split(":").Length != 2 ||
                         string.IsNullOrEmpty(userPass.Split(":")[0]) ||
                         string.IsNullOrEmpty(userPass.Split(":")[1]));

                var superUser = new ConnectionStringParameters(
                    User: userPass.Split(":")[0],
                    Pwd: userPass.Split(":")[1]
                );

                if (IsSuperAdmin(superUser))
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    var sw = new Stopwatch();

                    Console.Write("Database.Core.DCL.SetupDbAdmin...");
                    sw.Start();

                    setupDbAdmin.With(
                        new SetupDbAdmin.Command
                            { Password = "3911", Schema = "system", User = "heimdall" }, superUser);
                    Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms");

                    Console.WriteLine("::");
                    Console.WriteLine("::");
                    Console.Write("Database.Core.DDL.SetupIdentitySystem...");
                    sw.Restart();

                    //use application user, we use that role from now.
                    var connParams = new ConnectionStringParameters(User: "heimdall", Pwd: "3911");

                    setupIdentitySystem.With(new SetupIdentitySystem.Command { Schema = "system" }, connParams);
                    Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms");

                    Console.WriteLine("::");
                    Console.WriteLine("::");
                    Console.Write("Database.ConfigurationManagementSystem.SetupConfiguration...");
                    sw.Restart();
                    setupConfiguration.With(new SetupConfiguration.Command(), connParams);
                    Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms");

                    Console.WriteLine("::");
                    Console.WriteLine("::");
                    Console.Write("Database.Core.DDL.SetupOutbox...");
                    sw.Restart();
                    setupOutbox.With(new SetupOutbox.Command { Schema = "system" }, connParams);
                    Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms");

                    Console.WriteLine("::");
                    Console.WriteLine("::");
                    Console.Write("Database.Core.DCL.SetupApplicationUser...");
                    sw.Start();

                    setupApplicationUser.With(
                        new SetupApplicationUser.Command { Password = "3911", Schema = "system", User = "sathumper" },
                        superUser);
                    Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms");


                    //and a lot of other tables that we haven't defined yet

                    // input configurations!!! TODO:Missing

                    Console.ForegroundColor = _foregroundColor;
                }
            }

            catch (Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine();
                Console.WriteLine(e);
            }
        }
    }
}