using Insight.Infrastructure.Entities;
using Microsoft.AspNetCore.Identity;
using MongoDB.Driver;
using System.Globalization;
using System.Text;
using System.Text.Encodings.Web;

namespace Insight.Infrastructure.Services
{
    public class AuthenticatorService
    {
        private readonly IMongoDatabase _database;
        private readonly UserManager<InsightUser> _userManager;

        public AuthenticatorService(IMongoDatabase database, UserManager<InsightUser> userManager)
        {
            _database = database;
            _userManager = userManager;
        }

        public async Task<bool> GetStatusAsync(InsightUser user)
        {
            return await _userManager.GetTwoFactorEnabledAsync(user).ConfigureAwait(false);
        }

        public async Task<string?> GetKeyAsync(InsightUser user)
        {
            return await _userManager.GetAuthenticatorKeyAsync(user).ConfigureAwait(false);
        }

        public async Task<bool> ResetKeyAsync(InsightUser user)
        {
            var result = await _userManager.ResetAuthenticatorKeyAsync(user).ConfigureAwait(false);
            return result.Succeeded;
        }

        public async Task<bool> VerifyAsync(InsightUser user, string code)
        {
            code = code.Replace(" ", string.Empty).Replace("-", string.Empty);
            return await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, code).ConfigureAwait(false);
        }

        public async Task<bool> EnableAsync(InsightUser user)
        {
            var result = await _userManager.SetTwoFactorEnabledAsync(user, true).ConfigureAwait(false);
            return result.Succeeded;
        }

        public async Task<bool> DisableAsync(InsightUser user)
        {
            var result = await _userManager.SetTwoFactorEnabledAsync(user, false).ConfigureAwait(false);
            return result.Succeeded;
        }

        public async Task<bool> DeleteAsync(InsightUser user)
        {
            var result = await _userManager.SetTwoFactorEnabledAsync(user, false).ConfigureAwait(false);
            if (result.Succeeded is false) return false;

            result = await _userManager.RemoveAuthenticationTokenAsync(user, "[AspNetUserStore]", "AuthenticatorKey").ConfigureAwait(false);
            if (result.Succeeded is false) return false;

            return true;
        }

        public async Task<int> CountRecoveryCodesAsync(InsightUser user)
        {
            return await _userManager.CountRecoveryCodesAsync(user).ConfigureAwait(false);
        }

        public async Task<bool> UseRecoveryCodeAsync(InsightUser user, string recoveryCode)
        {
            var result = await _userManager.RedeemTwoFactorRecoveryCodeAsync(user, recoveryCode).ConfigureAwait(false);
            return result.Succeeded;
        }

        public async Task<IEnumerable<string>?> ResetRecoveryCodesAsync(InsightUser user, int count = 3)
        {
            return await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, count).ConfigureAwait(false);
        }

        public string GenerateQrCode(string email, string unformattedKey)
        {
            var encoder = UrlEncoder.Default;

            return string.Format(CultureInfo.InvariantCulture,
                @"otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6",
                encoder.Encode("Insight"),
                encoder.Encode(email),
                unformattedKey);
        }

        public static string HumanizeKey(string unformattedKey)
        {
            var result = new StringBuilder();
            int currentPosition = 0;

            while (currentPosition + 4 < unformattedKey.Length)
            {
                result.Append(unformattedKey.AsSpan(currentPosition, 4)).Append(' ');
                currentPosition += 4;
            }

            if (currentPosition < unformattedKey.Length)
            {
                result.Append(unformattedKey.AsSpan(currentPosition));
            }

            return result.ToString().ToLowerInvariant();
        }
    }
}