using Blazored.LocalStorage;
using Grpc.Core;
using Grpc.Net.Client.Web;
using Grpc.Net.Client;
using MudBlazor.Services;
using System.Text.Json;
using System.Text.Json.Serialization;
// Updated imports to use CMS protobuf instead of FrontOffice.BFF
using CMSMicroservice.Protobuf.Protos.Category;
using CMSMicroservice.Protobuf.Protos.City;
using CMSMicroservice.Protobuf.Protos.Package;
using CMSMicroservice.Protobuf.Protos.Products;
using CMSMicroservice.Protobuf.Protos.Transactions;
using CMSMicroservice.Protobuf.Protos.User;
using CMSMicroservice.Protobuf.Protos.UserCarts;
using CMSMicroservice.Protobuf.Protos.UserOrder;
using CMSMicroservice.Protobuf.Protos.UserWallet;
using CMSMicroservice.Protobuf.Protos.UserWalletHistory;
using CMSMicroservice.Protobuf.Protos.UserAddress;
using CMSMicroservice.Protobuf.Protos.Configuration;
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
using CMSMicroservice.Protobuf.Protos.Commission;
using CMSMicroservice.Protobuf.Protos.AppVersion;
using CMSMicroservice.Protobuf.Protos.SitePage;
using CMSMicroservice.Protobuf.Protos.SitePageSettings;
using CMSMicroservice.Protobuf.Protos.BlogPost;
using CMSMicroservice.Protobuf.Protos.BlogCategory;
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
using FrontOffice.Main.Utilities;
using FrontOffice.Main.Utilities.Seo;

namespace Microsoft.Extensions.DependencyInjection;

public static class ConfigureServices
{
    public static IServiceCollection AddCommonServices(this IServiceCollection services)
    {
        services.AddMudServices();
        services.AddBlazoredLocalStorage(config =>
        {
            config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
            config.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
            config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
            config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
            config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
            config.JsonSerializerOptions.WriteIndented = false;
        });

        // Access HttpContext for User-Agent
        services.AddHttpContextAccessor();

        // Register custom services
        services.AddSingleton<UserAuthInfo>();
        services.AddScoped<AuthService>();
        services.AddScoped<AuthDialogService>();
        services.AddScoped<GuestActionGate>();
        // Storefront services
        services.AddScoped<CartService>();
        services.AddScoped<ProductService>();
        services.AddScoped<CategoryService>();
        services.AddScoped<OrderService>();
        services.AddScoped<WalletService>();
        services.AddScoped<VATService>(); // Singleton برای cache روزانه
        // Package service
        services.AddScoped<PackageService>();
        // New services for Club, Network, Commission
        services.AddScoped<ClubMembershipService>();
        services.AddScoped<ClubConfigurationService>();
        services.AddScoped<NetworkMembershipService>();
        services.AddScoped<CommissionService>();
        // App Version Service for cache invalidation
        services.AddScoped<AppVersionService>();
        // Main Service for core functionality
        services.AddScoped<MainService>();
        // Site Page service for dynamic content (About, Contact)
        services.AddScoped<SitePageService>();
        // Blog Post service for landing page latest posts & blog pages
        services.AddScoped<BlogPostService>();
        // Blog Category service for blog sidebar filters
        services.AddScoped<BlogCategoryService>();
        // Discount Store services
        services.AddScoped<DiscountProductService>();
        services.AddScoped<DiscountCartService>();
        services.AddScoped<DiscountOrderService>();
        // Site Page Settings Service (simplified page management)
        services.AddScoped<SitePageSettingsService>();
        // Device detection: very light, dependency-free
        services.AddTransient<IDeviceDetector, DeviceDetector>();
        // PDF generation (Chromium only)
        services.AddSingleton<FrontOffice.Main.Utilities.Pdf.IChromiumPdfService, FrontOffice.Main.Utilities.Pdf.ChromiumPdfService>();
        
        // SignalR Token Notification Service
        services.AddScoped<TokenNotificationService>();

        // SEO
        services.AddScoped<SeoMetadataProvider>();
        services.AddScoped<SitemapGenerator>();

        return services;
    }

    public static IServiceCollection AddGrpcServices(this IServiceCollection services, IConfiguration configuration)
    {
        var baseUrl = ResolveGatewayUrl(configuration)
            ?? throw new InvalidOperationException("Gateway URL is missing. Set GW_URL or GwUrl.");

        var isHttp = baseUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase);

        // When the base URL is plain HTTP (e.g. in-cluster http://cms-svc:8080), we must force HTTP/1.1
        // so that GrpcChannel does not upgrade to h2c and trigger HTTP_1_1_REQUIRED from Kestrel.
        // For HTTPS the default negotiation is fine.
        services.AddScoped(sp =>
        {
            HttpMessageHandler inner = isHttp
                ? new SocketsHttpHandler
                {
                    MaxConnectionsPerServer = 10,
                    AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
                }
                : new HttpClientHandler
                {
                    MaxConnectionsPerServer = 10,
                    AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
                };

            return new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, inner))
            {
                Timeout = TimeSpan.FromMinutes(10),
                BaseAddress = new Uri(baseUrl),
                DefaultRequestVersion = isHttp ? System.Net.HttpVersion.Version11 : System.Net.HttpVersion.Version20,
                DefaultVersionPolicy = isHttp
                    ? System.Net.Http.HttpVersionPolicy.RequestVersionExact
                    : System.Net.Http.HttpVersionPolicy.RequestVersionOrHigher
            };
        });

        // Register gRPC clients with authentication - Updated for CMS
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Package.PackageContract.PackageContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.User.UserContract.UserContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserOrder.UserOrderContract.UserOrderContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserWallet.UserWalletContract.UserWalletContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Category.CategoryContract.CategoryContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Products.ProductsContract.ProductsContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Transactions.TransactionsContract.TransactionsContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserCarts.UserCartsContract.UserCartsContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.City.CityContract.CityContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserAddress.UserAddressContract.UserAddressContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserWalletHistory.UserWalletHistoryContract.UserWalletHistoryContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.ClubMembership.ClubMembershipContract.ClubMembershipContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.OtpToken.OtpTokenContract.OtpTokenContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Configuration.ConfigurationContract.ConfigurationContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.NetworkMembership.NetworkMembershipContract.NetworkMembershipContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Commission.CommissionContract.CommissionContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.AppVersion.AppVersionContract.AppVersionContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.SitePage.SitePageContract.SitePageContractClient>);
        services.AddScoped(CreateAuthenticatedClient<SitePageSettingsContract.SitePageSettingsContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.BlogPost.BlogPostContract.BlogPostContractClient>);
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.BlogCategory.BlogCategoryContract.BlogCategoryContractClient>);
        // Image Resolver Service
        services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.ImageResolver.ImageResolverContract.ImageResolverContractClient>);
        services.AddScoped<ImageCacheService>();
        // Discount Store gRPC clients
        services.AddScoped(CreateAuthenticatedClient<DiscountProductContract.DiscountProductContractClient>);
        services.AddScoped(CreateAuthenticatedClient<DiscountCategoryContract.DiscountCategoryContractClient>);
        services.AddScoped(CreateAuthenticatedClient<DiscountShoppingCartContract.DiscountShoppingCartContractClient>);
        services.AddScoped(CreateAuthenticatedClient<DiscountOrderContract.DiscountOrderContractClient>);

        return services;
    }

    private static string? ResolveGatewayUrl(IConfiguration configuration)
    {
        var envUrl = configuration["GW_URL"];
        if (!string.IsNullOrWhiteSpace(envUrl))
            return envUrl.TrimEnd('/');

        return configuration["GwUrl"]?.TrimEnd('/');
    }

    private static TClient CreateAuthenticatedClient<TClient>(IServiceProvider sp)
        where TClient : class
    {
        var httpClient = sp.GetRequiredService<HttpClient>();
        var localStorage = sp.GetRequiredService<ILocalStorageService>();
        var baseUrl = httpClient.BaseAddress?.ToString() ?? throw new InvalidOperationException("Base URL not configured");
        var isHttps = baseUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase);

        var credentials = CallCredentials.FromInterceptor(async (context, metadata) =>
        {
            try
            {
                var token = await localStorage.GetItemAsync<string>("auth:token");
                if (!string.IsNullOrWhiteSpace(token))
                {
                    metadata.Add("Authorization", $"Bearer {token}");
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                Console.WriteLine($"Token retrieval error: {ex.Message}");
#endif
            }
        });

        var channelCredentials = isHttps
            ? ChannelCredentials.Create(new SslCredentials(), credentials)
            : ChannelCredentials.Create(ChannelCredentials.Insecure, credentials);

        var channel = GrpcChannel.ForAddress(baseUrl, new GrpcChannelOptions
        {
            UnsafeUseInsecureChannelCallCredentials = !isHttps,
            Credentials = channelCredentials,
            HttpClient = httpClient,
            MaxReceiveMessageSize = 1000 * 1024 * 1024, // 1 GB
            MaxSendMessageSize = 1000 * 1024 * 1024     // 1 GB
        });

        return (TClient)Activator.CreateInstance(typeof(TClient), channel)!;
    }
}
