using System.Net;
using Microsoft.AspNetCore.HttpOverrides;
using Tiku.Api.Options;
using Tiku.Application.Tenancy;

namespace Tiku.Api.Configuration;

internal static class NetworkConfigurationExtensions
{
    internal static IServiceCollection AddNetworkConfiguration(
        this IServiceCollection services,
        IConfiguration configuration,
        IHostEnvironment environment)
    {
        services.AddOptions<TenantResolutionOptions>()
            .Bind(configuration.GetSection(TenantResolutionOptions.SectionName))
            .Validate(
                options => OptionsValidation.BeValidTenantResolutionOptions(options, configuration, environment.IsProduction()),
                "Production requires formal platform hosts, non-wildcard AllowedHosts, and trusted proxy addresses.")
            .ValidateOnStart();
        services.Configure<ForwardedHeadersOptions>(options =>
        {
            options.ForwardedHeaders =
                ForwardedHeaders.XForwardedFor |
                ForwardedHeaders.XForwardedHost |
                ForwardedHeaders.XForwardedProto;
            options.ForwardLimit = 1;
            options.KnownProxies.Clear();
            options.KnownIPNetworks.Clear();

            var resolution = configuration
                .GetSection(TenantResolutionOptions.SectionName)
                .Get<TenantResolutionOptions>() ?? new TenantResolutionOptions();
            foreach (var address in resolution.TrustedProxyAddresses)
            {
                if (IPAddress.TryParse(address, out var proxy))
                {
                    options.KnownProxies.Add(proxy);
                }
            }
        });
        services.AddOptions<DomainLifecycleOptions>()
            .Bind(configuration.GetSection("TenantDomains"));

        services.AddOptions<CorsOptions>()
            .Bind(configuration.GetSection(CorsOptions.SectionName))
            .ValidateDataAnnotations()
            .Validate(
                OptionsValidation.BeValidCorsOptions,
                "CORS origins must be absolute HTTP/HTTPS origins, and credentials require explicit origins.")
            .ValidateOnStart();

        var corsOptions = configuration
            .GetSection(CorsOptions.SectionName)
            .Get<CorsOptions>() ?? new CorsOptions();
        services.AddCors(options =>
        {
            options.AddPolicy(CorsOptions.PolicyName, policy =>
            {
                var origins = corsOptions.AllowedOrigins
                    .Where(origin => !string.IsNullOrWhiteSpace(origin))
                    .Select(origin => origin.Trim().TrimEnd('/'))
                    .Distinct(StringComparer.OrdinalIgnoreCase)
                    .ToArray();

                if (origins.Length > 0)
                {
                    policy.WithOrigins(origins);
                }

                policy
                    .WithHeaders(corsOptions.AllowedHeaders)
                    .WithMethods(corsOptions.AllowedMethods);

                if (corsOptions.AllowCredentials)
                {
                    policy.AllowCredentials();
                }
            });
        });

        return services;
    }
}
