using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Localization;
using System.Dynamic;
using System.Globalization;

namespace DigitalData.Core.API
{
    /// <summary>
    /// Provides extension methods for configuring localization services in an ASP.NET Core application.
    /// These methods simplify the integration of cookie-based localization by setting up resource paths
    /// and defining supported cultures.
    /// </summary>
    public static class LocalizationExtensions
    {
        /// <summary>
        /// Adds localized resources and view localization services to the application.
        /// </summary>
        /// <param name="services">The IServiceCollection to add services to.</param>
        /// <param name="resourcesPath">The path to the resource files used for localization.</param>
        /// <returns>The IServiceCollection for chaining.</returns>
        public static IServiceCollection AddCookieBasedLocalizer(this IServiceCollection services, string resourcesPath = "")
        {
            // Adds localization services with the specified resources path.
            services.AddLocalization(options => options.ResourcesPath = resourcesPath)

            // Adds MVC services with view localization and data annotations localization.
            .AddMvc().AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix)
                             .AddDataAnnotationsLocalization();

            return services;
        }

        /// <summary>
        /// Configures the application to use cookie-based localization with support for multiple cultures.
        /// </summary>
        /// <param name="app">The IApplicationBuilder to configure.</param>
        /// <param name="supportedCultureNames">A params array of supported culture names.</param>
        /// <returns>The IApplicationBuilder for chaining.</returns>
        public static IApplicationBuilder UseCookieBasedLocalizer(this IApplicationBuilder app, params string[] supportedCultureNames)
        {
            // Converts supported culture names into CultureInfo objects and checks for null or empty array.
            IList<CultureInfo> supportedCultures = supportedCultureNames.Select(cn => new CultureInfo(cn)).ToList();
            var defaultCultureInfo = supportedCultures.FirstOrDefault() ??
                throw new ArgumentNullException(nameof(supportedCultureNames), "Supported cultures cannot be empty.");

            // Configures localization options including default and supported cultures.
            var options = new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(culture: defaultCultureInfo.Name, uiCulture: defaultCultureInfo.Name),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures
            };
            options.RequestCultureProviders.Add(new QueryStringRequestCultureProvider());

            // Applies the localization settings to the application.
            app.UseRequestLocalization(options);
            return app;
        }

        /// <summary>
        /// Converts all localized strings to a dictionary.
        /// </summary>
        /// <param name="localizer">The <see cref="IStringLocalizer"/> instance containing the localized strings.</param>
        /// <returns>A dictionary containing all localized strings, where the key is the name of the string and the value is the localized value.</returns>
        public static Dictionary<string, string> ToDictionary(this IStringLocalizer localizer) => localizer.GetAllStrings().ToDictionary(ls => ls.Name, ls => ls.Value);

        /// <summary>
        /// Converts the localized strings from an <see cref="IStringLocalizer"/> to a dynamic object.
        /// </summary>
        /// <param name="localizer">The string localizer to get localized strings from.</param>
        /// <returns>A dynamic object containing all localized strings.</returns>
        public static dynamic ToDynamic(this IStringLocalizer localizer)
        {
            var expando = new ExpandoObject() as IDictionary<string, object>;
            foreach (var localizedString in localizer.GetAllStrings())
            {
                expando[localizedString.Name] = localizedString.Value;
            }
            return expando;
        }
    }
}