using global::EonaCat.Logger.Managers;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace EonaCat.Logger.EonaCatCoreLogger.Internal
{
    internal class SensitiveDataMasker
    {
        internal LoggerSettings LoggerSettings { get; }

        internal SensitiveDataMasker(LoggerSettings settings)
        {
            LoggerSettings = settings;
        }

        // Precompiled Regexes
        private static readonly Regex IpRegex = new Regex(@"\b(?:\d{1,3}\.){3}\d{1,3}\b(?!\d)", RegexOptions.Compiled);
        private static readonly Regex MacRegex = new Regex(@"\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b", RegexOptions.Compiled);
        private static readonly Regex EmailRegex = new Regex(@"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private static readonly Regex PasswordRegex = new Regex(@"(?i)(password\s*[:= ]\s*|pwd\s*[:= ]\s*)[^\s]+", RegexOptions.Compiled);
        private static readonly Regex DutchPasswordRegex = new Regex(@"(?i)(wachtwoord\s*[:= ]\s*|ww\s*=\s*)[^\s]+", RegexOptions.Compiled);
        private static readonly Regex CreditCardRegex = new Regex(@"\b(?:\d{4}[ -]?){3}\d{4}\b", RegexOptions.Compiled);
        private static readonly Regex SsnBsnRegex = new Regex(@"\b\d{3}-\d{2}-\d{4}\b|\b\d{9}\b", RegexOptions.Compiled);
        private static readonly Regex ApiKeyRegex = new Regex(@"\b[A-Za-z0-9-_]{20,}\b", RegexOptions.Compiled);
        private static readonly Regex PhoneGenericRegex = new Regex(@"\b(\+?\d{1,4}[-.\s]?)?(\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}\b", RegexOptions.Compiled);
        private static readonly Regex PhoneDutchRegex = new Regex(@"\b(\+31|0031|0|06)[-\s]?\d{8}\b", RegexOptions.Compiled);
        private static readonly Regex PhoneBelgiumRegex = new Regex(@"\b(\+32|0032|0|06)[-\s]?\d{8}\b", RegexOptions.Compiled);
        private static readonly Regex DobRegex = new Regex(@"\b\d{2}[/-]\d{2}[/-]\d{4}\b", RegexOptions.Compiled);
        private static readonly Regex PostalCodeDutchRegex = new Regex(@"\b\d{4}\s?[A-Z]{2}\b", RegexOptions.Compiled);
        private static readonly Regex IbanGenericRegex = new Regex(@"\b[A-Z]{2}\d{2}[A-Z0-9]{1,30}\b", RegexOptions.Compiled);
        private static readonly Regex IbanDutchRegex = new Regex(@"\bNL\d{2}[A-Z]{4}\d{10}\b", RegexOptions.Compiled);
        private static readonly Regex JwtRegex = new Regex(@"\b[A-Za-z0-9-_]{16,}\.[A-Za-z0-9-_]{16,}\.[A-Za-z0-9-_]{16,}\b", RegexOptions.Compiled);
        private static readonly Regex UrlSensitiveRegex = new Regex(@"\bhttps?:\/\/[^\s?]+(\?[^\s]+?[\&=](password|key|token|wachtwoord|sleutel))[^&\s]*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        private static readonly Regex LicenseKeyRegex = new Regex(@"\b[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}\b", RegexOptions.Compiled);
        private static readonly Regex PemKeyRegex = new Regex(@"-----BEGIN [A-Z ]+KEY-----[\s\S]+?-----END [A-Z ]+KEY-----", RegexOptions.Compiled);
        private static readonly Regex KvkRegex = new Regex(@"\b\d{8}|\d{12}\b", RegexOptions.Compiled);
        private static readonly Regex BtwRegex = new Regex(@"\bNL\d{9}B\d{2}\b", RegexOptions.Compiled);
        private static readonly Regex DutchDrivingLicenseRegex = new Regex(@"\b[A-Z0-9]{10,12}\b", RegexOptions.Compiled);
        private static readonly Regex ZorgnummerRegex = new Regex(@"\b\d{9}\b", RegexOptions.Compiled);
        private static readonly Regex DutchBankAccountRegex = new Regex(@"\b\d{9,10}\b", RegexOptions.Compiled);
        private static readonly Regex DutchPassportRegex = new Regex(@"\b[A-Z0-9]{9}\b", RegexOptions.Compiled);
        private static readonly Regex DutchIdDocRegex = new Regex(@"\b[A-Z]{2}\d{6,7}\b", RegexOptions.Compiled);

        internal virtual string MaskSensitiveInformation(string message)
        {
            if (string.IsNullOrEmpty(message))
            {
                return message;
            }

            if (LoggerSettings != null && LoggerSettings.UseDefaultMasking)
            {
                string mask = LoggerSettings.Mask ?? "***";

                message = IpRegex.Replace(message, mask);
                message = MacRegex.Replace(message, mask);
                message = EmailRegex.Replace(message, mask);
                message = PasswordRegex.Replace(message, $"password={mask}");
                message = DutchPasswordRegex.Replace(message, $"wachtwoord={mask}");
                message = CreditCardRegex.Replace(message, mask);
                message = SsnBsnRegex.Replace(message, mask);
                message = ApiKeyRegex.Replace(message, mask);
                message = PhoneGenericRegex.Replace(message, mask);
                message = PhoneDutchRegex.Replace(message, mask);
                message = PhoneBelgiumRegex.Replace(message, mask);
                message = DobRegex.Replace(message, mask);
                message = PostalCodeDutchRegex.Replace(message, mask);
                message = IbanGenericRegex.Replace(message, mask);
                message = IbanDutchRegex.Replace(message, mask);
                message = JwtRegex.Replace(message, mask);
                message = UrlSensitiveRegex.Replace(message, mask);
                message = LicenseKeyRegex.Replace(message, mask);
                message = PemKeyRegex.Replace(message, mask);
                message = KvkRegex.Replace(message, mask);
                message = BtwRegex.Replace(message, mask);
                message = DutchDrivingLicenseRegex.Replace(message, mask);
                message = ZorgnummerRegex.Replace(message, mask);
                message = DutchBankAccountRegex.Replace(message, mask);
                message = DutchPassportRegex.Replace(message, mask);
                message = DutchIdDocRegex.Replace(message, mask);
            }

            // Mask custom keywords
            if (LoggerSettings?.MaskedKeywords != null)
            {
                foreach (var keyword in LoggerSettings.MaskedKeywords)
                {
                    if (!string.IsNullOrWhiteSpace(keyword))
                    {
                        message = message.Replace(keyword, LoggerSettings.Mask);
                    }
                }
            }

            return message;
        }
    }
}
