using System;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using BO.AppServer.Business.Exceptions;
using BO.AppServer.Business.Security;
using BO.AppServer.Business.Security.Extensions;
using BO.AppServer.Data.Entity;
using BO.AppServer.Metadata.Configuration;
using BO.AppServer.Metadata.Enums;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NLog.LayoutRenderers;
using Quadarax.Foundation.Core.Business;

namespace BO.AppServer.Business.Services.Base
{
    public abstract class UserContextService : AbstractService
    {
        protected UserManager<IdentityUser> _manUser;
        protected UserRepo _repoUser;
        protected Configuration _configuration;

        protected UserContextService(IOptions<Configuration> config, UserRepo repoUser, UserManager<IdentityUser> userManager, IPrincipal currentPrincipal, ILoggerFactory logger) : base(MaySetDefaultPrincipal(currentPrincipal, config), logger)
        {
            _manUser = userManager ?? throw new ArgumentNullException(nameof(userManager));
            _repoUser = repoUser ?? throw new ArgumentNullException(nameof(repoUser));
            _configuration = config?.Value ?? throw new ArgumentNullException(nameof(config));
        }
        

        protected User GetCurrentUser()
        {
            var userIdt = _manUser.FindByNameAsync(CurrentPrincipal.Identity.Name).Result;
            return _repoUser.GetByIfReference(userIdt.Id);
        }
        protected long GetCurrentUserId()
        {
            var user = GetCurrentUser();
            return user.Id;
        }

        protected async Task<bool> HasUserElevation(string alternativeCurrentUserName)
        {
            var owner = string.IsNullOrEmpty(alternativeCurrentUserName) ? CurrentPrincipal.Identity.Name : alternativeCurrentUserName;
            var result = await _manUser.HasUserRoleAny(owner, RoleUtils.GetElevatedRoles());
            Log.LogTrace($"User '{owner}' {(result ? "has" : "hasn't")} elevation.");
            return result;
        }

        private static IPrincipal MaySetDefaultPrincipal(IPrincipal principal, IOptions<Configuration> config)
        {
            if (principal?.Identity == null || principal.Identity.Name == "genericIdentity")
                principal = new GenericPrincipal(new GenericIdentity(config.Value.System.AccountSystem.Name),new[] { RoleEnum.System.ToString() });
            return principal;
        }


        protected long ArgumentAsLong(string argumentName, string value)
        {
            if (!long.TryParse(value, out var result))
            {
                throw new CannotCastArgumentException(argumentName, value, typeof(long));
            }

            return result;
        }
    }
}
