using ZB.MOM.WW.Configuration;
using ZB.MOM.WW.GalaxyRepository;

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

/// <summary>
/// Gateway-side startup validation for the shared <see cref="GalaxyRepositoryOptions"/>. The
/// <c>ZB.MOM.WW.GalaxyRepository</c> package binds the options but deliberately ships no validator
/// (see <c>A2-galaxyrepository-adoption-handoff.md</c>); the gateway owns the rule because it is the
/// process that writes the snapshot. When persistence is on, the snapshot path must be a valid,
/// rooted path on the running host for the same reason the auth DB path must be (SEC-33): a
/// non-rooted value silently resolves against the launch working directory.
/// </summary>
public sealed class GalaxyRepositoryOptionsValidator : OptionsValidatorBase<GalaxyRepositoryOptions>
{
    // See GatewayOptionsValidator for why this is nullable and what null means.
    private readonly string? _contentRootPath;

    /// <summary>
    /// Initializes a new instance of the <see cref="GalaxyRepositoryOptionsValidator"/> class for
    /// the dependency-injection path, taking the content root from the host environment.
    /// </summary>
    /// <param name="environment">The host environment.</param>
    public GalaxyRepositoryOptionsValidator(IHostEnvironment environment)
    {
        ArgumentNullException.ThrowIfNull(environment);
        _contentRootPath = environment.ContentRootPath;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="GalaxyRepositoryOptionsValidator"/> class for
    /// unit tests and non-DI callers.
    /// </summary>
    /// <param name="contentRootPath">
    /// Content root to test the snapshot path against; <see langword="null"/> leaves the
    /// content-root rule inactive.
    /// </param>
    internal GalaxyRepositoryOptionsValidator(string? contentRootPath = null)
    {
        _contentRootPath = contentRootPath;
    }

    /// <inheritdoc />
    protected override void Validate(ValidationBuilder builder, GalaxyRepositoryOptions options)
    {
        if (!options.PersistSnapshot)
        {
            // Persistence disabled: the snapshot path is never used, so nothing to validate.
            return;
        }

        if (string.IsNullOrWhiteSpace(options.SnapshotCachePath))
        {
            builder.Add(
                "MxGateway:Galaxy:SnapshotCachePath is required when MxGateway:Galaxy:PersistSnapshot is true.");
            return;
        }

        GatewayConfigPathRules.AddIfInvalidPath(
            options.SnapshotCachePath,
            "MxGateway:Galaxy:SnapshotCachePath must be a valid filesystem path.",
            builder);
        GatewayConfigPathRules.AddIfNotRooted(
            options.SnapshotCachePath,
            "MxGateway:Galaxy:SnapshotCachePath must be an absolute (rooted) path so the Galaxy snapshot never lands in the launch working directory.",
            builder);
        GatewayConfigPathRules.AddIfUnderContentRoot(
            options.SnapshotCachePath,
            _contentRootPath,
            $"MxGateway:Galaxy:SnapshotCachePath must not be inside the application directory ({_contentRootPath}). The upgrade procedure renames that directory, so the cached snapshot is discarded on every deploy and the gateway starts cold.",
            builder);
    }
}
