using eSuite.API.SingleSignOn;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using System.Text.Json;
using System.Text.RegularExpressions;
using e_suite.API.Common.extensions;

namespace eSuite.API.Translation;

[AttributeUsage(AttributeTargets.Field)]
public class NamespaceValueAttribute : Attribute
{
    public string Value { get; }

    public NamespaceValueAttribute(string value)
    {
        Value = value;
    }
}

public enum Namespaces
{
    [NamespaceValue("common")]
    Common,

    [NamespaceValue("mailTypes")]
    MailTypes,

    [NamespaceValue("htmlIsland")]
    HtmlIsland
}

public static class NamespaceExtensions
{
    public static string ToNamespaceString(this Namespaces ns)
    {
        var type = ns.GetType();
        var member = type.GetMember(ns.ToString()).FirstOrDefault();

        var attr = member?
            .GetCustomAttributes(typeof(NamespaceValueAttribute), false)
            .Cast<NamespaceValueAttribute>()
            .FirstOrDefault();

        return attr?.Value ?? ns.ToString();
    }
}

public static class I18nInterpolation
{
    private static readonly Regex TokenRegex = new Regex(@"{{\s*(\w+)\s*}}",
        RegexOptions.Compiled);

    public static string Interpolate(string template, IDictionary<string, object> values)
    {
        if (template == null)
            return string.Empty;

        return TokenRegex.Replace(template, match =>
        {
            var key = match.Groups[1].Value;

            if (values != null && values.TryGetValue(key, out var val))
                return val?.ToString() ?? string.Empty;

            return match.Value;
        });
    }
}

public interface ITranslator
{
    string T(string key, object values = null);
}

public class Translator : ITranslator
{
    private readonly IDictionary<string, string> _translations;

    public Translator(IDictionary<string, string> translations)
    {
        _translations = translations;
    }

    public string T(string key, object values = null)
    {
        if (!_translations.TryGetValue(key, out var template))
            return key;

        var dict = values?
            .GetType()
            .GetProperties()
            .ToDictionary(p => p.Name, p => p.GetValue(values));

        return I18nInterpolation.Interpolate(template, dict);
    }
}

public static class LocaleFallback
{
    public static IEnumerable<string> ResolveFallbacks(string locale, string defaultLocale = "en")
    {
        if (!string.IsNullOrWhiteSpace(locale))
        {
            var parts = locale.Split('-');

            // Default first
            if (!string.Equals(locale, defaultLocale, StringComparison.OrdinalIgnoreCase))
                yield return defaultLocale;

            // Language-only
            if (parts.Length > 1)
                yield return parts[0];

            // Full locale last (most specific)
            yield return locale;
        }
        else
        {
            yield return defaultLocale;
        }
    }

}

public interface IJsonLocalizationService
{
    Task<IDictionary<string, string>> LoadNamespaceAsync(string locale, string ns);
}

public class JsonLocalizationService : IJsonLocalizationService
{
    private readonly IHttpClientFacade _http;
    private readonly IMemoryCache _cache;
    private readonly string _baseUrl;

    public JsonLocalizationService(
        IHttpClientFacade http,
        IMemoryCache cache,
        IConfiguration configuration
            )
    {
        _http = http;
        _cache = cache;

        _baseUrl = configuration.GetConfigValue("BASE_URL", "baseUrl", "http://localhost:3000");
    }

    public Task<IDictionary<string, string>> LoadNamespaceAsync(string locale, string ns)
    {
        var cacheKey = $"i18n:{locale}:{ns}";

        return _cache.GetOrCreateAsync(cacheKey, async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
            return await LoadNamespaceInternalAsync(locale, ns);
        });
    }

    private async Task<IDictionary<string, string>> LoadNamespaceInternalAsync(string locale, string ns)
    {
        var result = new Dictionary<string, string>();

        foreach (var loc in LocaleFallback.ResolveFallbacks(locale))
        {
            var url = new Uri($"{_baseUrl}/locales/{loc}/{ns}.json");

            try
            {
                var json = await _http.GetStringAsync(url, CancellationToken.None);
                var dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);

                foreach (var kvp in dict)
                    result[kvp.Key] = kvp.Value;
            }
            catch
            {
                // ignore missing files
            }
        }

        return result;
    }
}

public interface ITranslatorFactory
{
    string Locale { get; set; }
    Task<ITranslator> Use(params Namespaces[] namespaces);
}

public class TranslatorFactory : ITranslatorFactory
{
    private readonly IJsonLocalizationService _localizer;
    public string Locale { get; set; } = "en-GB";

    public TranslatorFactory(IJsonLocalizationService localizer)
    {
        _localizer = localizer;
    }

    public async Task<ITranslator> Use(params Namespaces[] namespaces)
    {
        var merged = new Dictionary<string, string>();

        foreach (var ns in namespaces)
        {
            var nsString = ns.ToNamespaceString();
            var dict = await _localizer.LoadNamespaceAsync(Locale, nsString);

            foreach (var kvp in dict)
                merged[kvp.Key] = kvp.Value;
        }

        return new Translator(merged);
    }
}