using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Edge.Core
{
    public static class ExtentionMethod
    {
        /// <summary>
        /// Extract the localized content string from source, the source should follow the format-> lang-zh-cn:稳Dart加油机lang-en-us:WayneDartPump
        /// </summary>
        /// <param name="source">should follow the format-> lang-zh-cn:稳Dart加油机lang-en-us:WayneDartPumplang-xx:xContent</param>
        /// <param name="language">like-> en-us, zh-cn, or en, zh</param>
        /// <returns>if target language is not searched from source, then content with 'en' locale will be returned, if 'en' locale is not searched, content with 'zh-cn' locale will be returned original, otherwise source will be returned</returns>
        public static string LocalizedContent(this string source, string language)
        {
            if (string.IsNullOrEmpty(source)) return source;
            //if (string.IsNullOrEmpty(language)) return source;
            //var langDeclareRegexStr = @"(lang-\w\w-\w\w\:).+?((?=lang-\w\w-\w\w\:)|(?=$))";
            var allLangDeclareRegexStr = @"(lang-\w\w(-\w\w)?\:).+?((?=lang-\w\w(-\w\w)?\:)|(?=$))";
            var allLangMatches = Regex.Matches(source, allLangDeclareRegexStr).Cast<Match>();
            foreach (var langMatch in allLangMatches)
            {
                var targetLangPrefix = "^lang-" + language + @"(-\w\w)?\:";
                var m = Regex.Match(langMatch.Value, targetLangPrefix, RegexOptions.IgnoreCase);
                if (m.Success)
                    return langMatch.Value.Substring(m.Length);
            }

            var default_match =
                allLangMatches.FirstOrDefault(m =>
                    m.Value.Split(':')[0].Contains("en", StringComparison.OrdinalIgnoreCase));
            if (default_match == null)
                default_match = allLangMatches.FirstOrDefault(m =>
                    m.Value.Split(':')[0].Contains("zh-cn", StringComparison.OrdinalIgnoreCase));
            return default_match?.Value?.Substring(default_match.Value.Split(':')[0].Length + 1) ?? source;
        }

        /// <summary>
        /// Extract the localized content string from the json schema source.
        ///     the multi-language text in json schema is like-> "title": "lang-zh-cn:停止位lang-en-us:StopBits"
        /// </summary>
        /// <param name="jsonSchemaSource"></param>
        /// <param name="language">like-> en-us, zh-cn, or en, zh</param>
        /// <returns></returns>
        public static string LocalizedJsonSchema(this string jsonSchemaSource, string language)
        {
            if (string.IsNullOrEmpty(jsonSchemaSource)) return jsonSchemaSource;
            //if (string.IsNullOrEmpty(language)) return jsonSchemaSource;
            // sample:   "title": "lang-zh-cn:停止位lang-en-us:StopBits"
            var targetContentRegexStr = @"(?<=\""(title|infoText)\""\s*?\:\s*?\"").+?((?=\"")|(?=$))";
            var matches = Regex.Matches(jsonSchemaSource, targetContentRegexStr, RegexOptions.Multiline | RegexOptions.IgnoreCase).Cast<Match>();

            foreach (var ma in matches)
            {
                jsonSchemaSource = jsonSchemaSource.Replace(ma.Value, ma.Value.LocalizedContent(language));
            }

            //var allInfoTextContentRegexStr = @"(?<=\""infoText\""\s*?\:\s*?\"").+?((?=\"")|(?=$))";
            //var allInfoTextContentMatches = Regex.Matches(jsonSchemaSource, allInfoTextContentRegexStr, RegexOptions.Multiline | RegexOptions.IgnoreCase).Cast<Match>();

            //foreach (var infoTextNodeContentMatch in allInfoTextContentMatches)
            //{
            //    jsonSchemaSource =
            //        jsonSchemaSource.Replace(infoTextNodeContentMatch.Value,
            //            infoTextNodeContentMatch.Value.LocalizedContent(language));
            //}

            return jsonSchemaSource;
        }

        /// <summary>
        /// Search the target byte list in src.
        /// </summary>
        /// <param name="src"></param>
        /// <param name="target"></param>
        /// <returns>-1 indicates can not find target in src, otherwise, return the index in src, 0 based.</returns>
        public static int IndexOfSubList(this List<byte> src, List<byte> target)
        {
            if (src.Count < target.Count) return -1;
            int everFound = 0;
            int srcIndex = 0;
            int targetIndex = 0;
            for (int i = 0; i < src.Count; i++)
            {
                //if (srcIndex == src.Count - 1)
                //{
                //    if (everFound == target.Count) return srcIndex - target.Count + 1;
                //    else return -1;
                //}

                if (everFound == target.Count) return srcIndex - target.Count;
                if (src[srcIndex] == target[targetIndex])
                {
                    everFound++;
                    srcIndex++;
                    targetIndex++;
                }
                else
                {
                    if (everFound > 0)
                    { targetIndex = 0; everFound = 0; }
                    else
                    {
                        srcIndex++;
                    }
                }
            }

            if (everFound == target.Count) return srcIndex - target.Count;
            return -1;
        }

        /// <summary>
        /// create a custom logger if it does not exists, otherwise get the logger.
        /// This is only for NLog implementation.
        /// </summary>
        /// <param name="loggerFactory"></param>
        /// <param name="loggerFileName">custom logger file name will be created or get.</param>
        /// <returns></returns>
        public static ILogger CreateOrGetCustomLogger(this ILoggerFactory loggerFactory, string loggerFileName, LogLevel logLevel)
        {
            if (string.IsNullOrEmpty(loggerFileName)) throw new ArgumentException("loggerFileName must not be null or empty");
            ILogger logger = null;
            switch (logLevel)
            {
                case LogLevel.Trace:
                    logger = loggerFactory.CreateLogger("DynamicPrivate_Trace_" + loggerFileName);
                    break;
                case LogLevel.Debug:
                    logger = loggerFactory.CreateLogger("DynamicPrivate_Debug_" + loggerFileName);
                    break;
                case LogLevel.Information:
                    logger = loggerFactory.CreateLogger("DynamicPrivate_Info_" + loggerFileName);
                    break;
                case LogLevel.Warning:
                    logger = loggerFactory.CreateLogger("DynamicPrivate_Warn_" + loggerFileName);
                    break;
                case LogLevel.Error:
                    logger = loggerFactory.CreateLogger("DynamicPrivate_Error_" + loggerFileName);
                    break;
                case LogLevel.Critical:
                    logger = loggerFactory.CreateLogger("DynamicPrivate_Fatal_" + loggerFileName);
                    break;
            }

            return logger;
        }
    }
}
