using System;
using System.IO;
using StellaOps.Authority.Plugin.Standard;
using StellaOps.Cryptography;

namespace StellaOps.Authority.Plugin.Standard.Tests;

public class StandardPluginOptionsTests
{
    [Fact]
    public void Validate_AllowsBootstrapWhenCredentialsProvided()
    {
        var options = new StandardPluginOptions
        {
            BootstrapUser = new BootstrapUserOptions
            {
                Username = "admin",
                Password = "Bootstrap1!",
                RequirePasswordReset = true
            }
        };

        options.Validate("standard");
    }

    [Fact]
    public void Validate_Throws_WhenBootstrapUserIncomplete()
    {
        var options = new StandardPluginOptions
        {
            BootstrapUser = new BootstrapUserOptions
            {
                Username = "admin",
                Password = null
            }
        };

        var ex = Assert.Throws<InvalidOperationException>(() => options.Validate("standard"));
        Assert.Contains("bootstrapUser", ex.Message, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void Validate_Throws_WhenLockoutWindowMinutesInvalid()
    {
        var options = new StandardPluginOptions
        {
            Lockout = new LockoutOptions
            {
                Enabled = true,
                MaxAttempts = 5,
                WindowMinutes = 0
            }
        };

        var ex = Assert.Throws<InvalidOperationException>(() => options.Validate("standard"));
        Assert.Contains("lockout.windowMinutes", ex.Message, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void Normalize_ResolvesRelativeTokenSigningDirectory()
    {
        var configDir = Path.Combine(Path.GetTempPath(), "stellaops-standard-plugin", Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(configDir);

        try
        {
            var configPath = Path.Combine(configDir, "standard.yaml");
            var options = new StandardPluginOptions
            {
                TokenSigning = { KeyDirectory = "../keys" }
            };

            options.Normalize(configPath);

            var expected = Path.GetFullPath(Path.Combine(configDir, "../keys"));
            Assert.Equal(expected, options.TokenSigning.KeyDirectory);
        }
        finally
        {
            if (Directory.Exists(configDir))
            {
                Directory.Delete(configDir, recursive: true);
            }
        }
    }

    [Fact]
    public void Normalize_PreservesAbsoluteTokenSigningDirectory()
    {
        var absolute = Path.Combine(Path.GetTempPath(), "stellaops-standard-plugin", Guid.NewGuid().ToString("N"), "keys");
        var options = new StandardPluginOptions
        {
            TokenSigning = { KeyDirectory = absolute }
        };

        options.Normalize(Path.Combine(Path.GetTempPath(), "config", "standard.yaml"));

        Assert.Equal(Path.GetFullPath(absolute), options.TokenSigning.KeyDirectory);
    }

    [Fact]
    public void Validate_Throws_WhenPasswordHashingMemoryInvalid()
    {
        var options = new StandardPluginOptions
        {
            PasswordHashing = new PasswordHashOptions
            {
                MemorySizeInKib = 0
            }
        };

        var ex = Assert.Throws<InvalidOperationException>(() => options.Validate("standard"));
        Assert.Contains("memory", ex.Message, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void Validate_Throws_WhenPasswordHashingIterationsInvalid()
    {
        var options = new StandardPluginOptions
        {
            PasswordHashing = new PasswordHashOptions
            {
                Iterations = 0
            }
        };

        var ex = Assert.Throws<InvalidOperationException>(() => options.Validate("standard"));
        Assert.Contains("iteration", ex.Message, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void Validate_Throws_WhenPasswordHashingParallelismInvalid()
    {
        var options = new StandardPluginOptions
        {
            PasswordHashing = new PasswordHashOptions
            {
                Parallelism = 0
            }
        };

        var ex = Assert.Throws<InvalidOperationException>(() => options.Validate("standard"));
        Assert.Contains("parallelism", ex.Message, StringComparison.OrdinalIgnoreCase);
    }
}
