using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.GalaxyRepository;
using ZB.MOM.WW.MxGateway.Server;
using ZB.MOM.WW.MxGateway.Server.Configuration;

namespace ZB.MOM.WW.MxGateway.Tests.Configuration;

/// <summary>
/// Gateway-owned validation of the shared <see cref="GalaxyRepositoryOptions"/> (SEC-33): the Galaxy
/// package binds the options but ships no validator, so the gateway rejects a persisted snapshot
/// whose path is blank, invalid, or non-rooted on the running host, and supplies a rooted per-OS
/// default when the shipped config leaves the path blank.
/// </summary>
public sealed class GalaxyRepositoryOptionsValidatorTests
{
    /// <summary>Verifies a blank snapshot path with persistence enabled fails validation.</summary>
    [Fact]
    public void Validate_Fails_WhenPersistSnapshotAndPathBlank()
    {
        GalaxyRepositoryOptions options = new() { PersistSnapshot = true, SnapshotCachePath = "" };
        ValidateOptionsResult result = new GalaxyRepositoryOptionsValidator().Validate(null, options);
        Assert.True(result.Failed);
        Assert.Contains(result.Failures!, f => f.Contains("MxGateway:Galaxy:SnapshotCachePath"));
    }

    /// <summary>Verifies a non-rooted snapshot path with persistence enabled fails validation.</summary>
    [Fact]
    public void Validate_Fails_WhenPersistSnapshotAndPathNotRooted()
    {
        GalaxyRepositoryOptions options = new()
        {
            PersistSnapshot = true,
            SnapshotCachePath = "galaxy-snapshot.json",
        };
        ValidateOptionsResult result = new GalaxyRepositoryOptionsValidator().Validate(null, options);
        Assert.True(result.Failed);
        Assert.Contains(
            result.Failures!,
            f => f.Contains("MxGateway:Galaxy:SnapshotCachePath") && f.Contains("rooted"));
    }

    /// <summary>Verifies a blank path passes when persistence is disabled (the path is never used).</summary>
    [Fact]
    public void Validate_Succeeds_WhenPersistSnapshotDisabled()
    {
        GalaxyRepositoryOptions options = new() { PersistSnapshot = false, SnapshotCachePath = "" };
        ValidateOptionsResult result = new GalaxyRepositoryOptionsValidator().Validate(null, options);
        Assert.True(result.Succeeded);
    }

    /// <summary>Verifies a valid, host-rooted snapshot path with persistence enabled passes.</summary>
    [Fact]
    public void Validate_Succeeds_WhenPersistSnapshotAndPathRooted()
    {
        GalaxyRepositoryOptions options = new()
        {
            PersistSnapshot = true,
            SnapshotCachePath = Path.Combine(Path.GetTempPath(), "galaxy-snapshot.json"),
        };
        ValidateOptionsResult result = new GalaxyRepositoryOptionsValidator().Validate(null, options);
        Assert.True(result.Succeeded);
    }

    /// <summary>
    /// Verifies an absolute snapshot path inside the application directory fails. Rooted is not the
    /// same as safe: the upgrade procedure renames that directory, so a snapshot cached there is
    /// discarded on every deploy and the gateway starts cold each time.
    /// </summary>
    [Fact]
    public void Validate_Fails_WhenSnapshotPathIsUnderContentRoot()
    {
        string contentRoot = Path.Combine(Path.GetTempPath(), $"mxgw-root-{Guid.NewGuid():N}");
        GalaxyRepositoryOptions options = new()
        {
            PersistSnapshot = true,
            SnapshotCachePath = Path.Combine(contentRoot, "galaxy-snapshot.json"),
        };

        ValidateOptionsResult result =
            new GalaxyRepositoryOptionsValidator(contentRoot).Validate(null, options);

        Assert.True(result.Failed);
        Assert.Contains(
            result.Failures!,
            f => f.Contains("MxGateway:Galaxy:SnapshotCachePath")
                && f.Contains("must not be inside the application directory"));
    }

    /// <summary>Verifies a snapshot path outside the application directory still passes.</summary>
    [Fact]
    public void Validate_Succeeds_WhenSnapshotPathIsOutsideContentRoot()
    {
        string contentRoot = Path.Combine(Path.GetTempPath(), $"mxgw-root-{Guid.NewGuid():N}");
        GalaxyRepositoryOptions options = new()
        {
            PersistSnapshot = true,
            SnapshotCachePath =
                Path.Combine(Path.GetTempPath(), $"mxgw-data-{Guid.NewGuid():N}", "galaxy-snapshot.json"),
        };

        ValidateOptionsResult result =
            new GalaxyRepositoryOptionsValidator(contentRoot).Validate(null, options);

        Assert.True(result.Succeeded);
    }

    /// <summary>
    /// Verifies the gateway supplies a rooted per-OS default when the shipped config leaves
    /// SnapshotCachePath blank, so the removed appsettings literal is not needed and validation
    /// passes on any host (SEC-33). Resolving the options triggers the registered validator.
    /// </summary>
    [Fact]
    public void Build_DefaultsBlankSnapshotCachePathToRootedDefault()
    {
        using WebApplication app = GatewayApplication.Build([]);

        GalaxyRepositoryOptions options =
            app.Services.GetRequiredService<IOptions<GalaxyRepositoryOptions>>().Value;

        Assert.False(string.IsNullOrWhiteSpace(options.SnapshotCachePath));
        Assert.True(Path.IsPathRooted(options.SnapshotCachePath));
    }
}
