using System;
using System.Collections.Generic;
using System.Security.Principal;
using System.Threading.Tasks;
using BO.AppServer.Metadata.Configuration;
using BO.AppServer.Metadata.Dto;
using BO.AppServer.Metadata.Enums;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Quadarax.Foundation.Core.Business;
using Quadarax.Foundation.Core.Data.Interface.Entity.Dto;

namespace BO.AppServer.Business.Services
{


    public class ConfigurationService : AbstractService
    {
        #region *** Constants ***
        private const string CS_WRK_DEV_NAME = "TestWorkspace";
        private const string CS_WRK_DEV_APIPWD = "test";
        private const string CS_USR_DEV_NAME = "test";
        private const string CS_USR_DEV_PWD = "password";
        private const string CS_USR_DEV_EML = "test@boo.com";
        private const string CS_BP_DEV_CODE = "UNLIMITED";
        #endregion


        private IServiceProvider _serviceProvider;

        public Configuration Configuration { get; }

        public ConfigurationService(IOptions<Configuration> config,
            IServiceProvider serviceProvider,
            IPrincipal currentPrincipal, 
            ILoggerFactory logger) : base(currentPrincipal, logger)
        {
            if (config == null)
                throw new ArgumentNullException(nameof(config));
            Configuration = config.Value;

            _serviceProvider = serviceProvider;
        }

        public async Task<ResultPlain> Install()
        {

            using (var scope = _serviceProvider.CreateScope())
            {
                var srvUsers = scope.ServiceProvider.GetRequiredService<UserService>();
                

                await srvUsers.EnsureRolesAsync();
                    
                await EnsureUser(srvUsers, Configuration.System.AccountSystem.Name,
                    Configuration.System.AccountSystem.Password,
                    Configuration.System.AccountSystem.Email,
                    Configuration.System.AccountSystem.CultureLcid, new[]
                    {
                        RoleEnum.System,
                    });

                await EnsureUser(srvUsers, Configuration.System.AccountConsole.Name,
                    Configuration.System.AccountConsole.Password,
                    Configuration.System.AccountConsole.Email,
                    Configuration.System.AccountConsole.CultureLcid, new[]
                    {
                        RoleEnum.System,
                        RoleEnum.Console,
                        RoleEnum.SuperAdmin
                    });

                await EnsureUser(srvUsers, Configuration.System.AccountAdmin.Name,
                    Configuration.System.AccountAdmin.Password,
                    Configuration.System.AccountAdmin.Email,
                    Configuration.System.AccountAdmin.CultureLcid, new[]
                    {
                        RoleEnum.User,
                        RoleEnum.SuperAdmin
                    });

                await EnsureUser(srvUsers, Configuration.System.AccountProcess.Name,
                    Configuration.System.AccountProcess.Password,
                    Configuration.System.AccountProcess.Email,
                    Configuration.System.AccountProcess.CultureLcid, new[]
                    {
                        RoleEnum.System,
                        RoleEnum.Service
                    });
            }
            return new ResultPlain();
        }

        public async Task<ResultPlain> InstallDev()
        {

            using (var scope = _serviceProvider.CreateScope())
            {
                var srvCatalogues = scope.ServiceProvider.GetRequiredService<CatalogueService>();
                var srvUsers = scope.ServiceProvider.GetRequiredService<UserService>();
                var srvWorkspaces = scope.ServiceProvider.GetRequiredService<WorkspaceService>();

                var task0 = srvCatalogues.CreateBillingPlanAsync(new BillingPlanCDto()
                {
                    Name = "Unlimited",
                    Code = CS_BP_DEV_CODE,
                    Description = "This plan is only for testing purpose",
                    PstinitialCredits = 1000,
                    PstcreditsPerItem = 1,
                    Pstwatermark = true,
                    Pstquality = 1,
                    PstprocessProfile = "PRC01",
                    Psttest = true,
                    Price = 1,
                    Currency = "EUR",
                    IsCustom = false,
                    IsHidden = false,
                    IsEnabled = true
                }, true);

                var task1 = srvCatalogues.CreateMimeTypeAsync(new MimeTypeCDto()
                {
                    Mimetype1 = "text/plain",
                    Description = "Plain text file",
                    Extensions = "txt",
                    IsEnabled = true
                }, true);

                var task2 = srvCatalogues.CreateMimeTypeAsync(new MimeTypeCDto()
                {
                    Mimetype1 = "application/octet-stream",
                    Description = "Binary files",
                    Extensions = "bin",
                    IsEnabled = true
                }, true);


                var task3 = EnsureUser(srvUsers, CS_USR_DEV_NAME, CS_USR_DEV_PWD, CS_USR_DEV_EML, 1029,
                    new[] { RoleEnum.User, RoleEnum.Admin });

                Task.WhenAll(task0, task1, task2, task3)
                    .ContinueWith(async (t) =>
                    {

                        if (await srvWorkspaces.ExistsWorkspace(WorkspaceIdentificationTypeEnum.Name, CS_WRK_DEV_NAME))
                            return await srvWorkspaces.GetWorkspace(WorkspaceIdentificationTypeEnum.Name, CS_WRK_DEV_NAME);

                        return await srvWorkspaces.CreateWorkspaceAsync(new WorkspaceCDto()
                        {
                            Name = CS_WRK_DEV_NAME,
                            Apipassword = CS_WRK_DEV_APIPWD,
                            BillingPlanCode = CS_BP_DEV_CODE,
                            AssignedUserName = CS_USR_DEV_NAME
                        });
                    }).Wait();
            }
            return new ResultPlain();
        }

        public void LogInfo(string message)
        {
            Log.LogInformation(message);
        }

        protected async Task EnsureUser(UserService srvUsers, string userName, string userPassword, string userEmail, int prefferedLCID,
            RoleEnum[] roles)
        {
            if (!(srvUsers.ExistsUserByNameAsync(userName).Result.Value))
                await srvUsers.CreateUserAsync(userName,
                    userPassword,
                    userEmail,
                    prefferedLCID, roles);
            else
                await srvUsers.EnusreUserRolesAsync(userName, roles);
        }

    }
}
