// Tests for service import shadowing detection.
// Go reference: accounts.go serviceImportShadowed (~line 2015).

using NATS.Server.Auth;
using NATS.Server.Imports;
using NATS.Server.Subscriptions;

namespace NATS.Server.Auth.Tests.Auth;

public class ImportShadowingTests
{
    private static Account CreateAccount(string name) => new(name);

    private static Subscription MakeSub(string subject) =>
        new() { Subject = subject, Sid = subject };

    /// <summary>
    /// Adds a service import entry directly to the account's import map (bypassing
    /// export/cycle checks) so that shadowing tests can exercise the import map iteration.
    /// </summary>
    private static void RegisterServiceImport(Account account, string fromSubject)
    {
        var dest = CreateAccount("Dest");
        var si = new ServiceImport
        {
            DestinationAccount = dest,
            From = fromSubject,
            To = fromSubject,
        };
        account.Imports.AddServiceImport(si);
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void ServiceImportShadowed_NoLocalSubs_ReturnsFalse()
    {
        var account = CreateAccount("A");

        var result = account.ServiceImportShadowed("orders.create");

        result.ShouldBeFalse();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void ServiceImportShadowed_ExactMatch_ReturnsTrue()
    {
        var account = CreateAccount("A");
        account.SubList.Insert(MakeSub("orders.create"));

        var result = account.ServiceImportShadowed("orders.create");

        result.ShouldBeTrue();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void ServiceImportShadowed_WildcardMatch_ReturnsTrue()
    {
        // Local subscription "orders.*" shadows import on "orders.create"
        var account = CreateAccount("A");
        account.SubList.Insert(MakeSub("orders.*"));

        var result = account.ServiceImportShadowed("orders.create");

        result.ShouldBeTrue();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void ServiceImportShadowed_GtWildcard_ReturnsTrue()
    {
        // Local subscription "orders.>" shadows import on "orders.create.new"
        var account = CreateAccount("A");
        account.SubList.Insert(MakeSub("orders.>"));

        var result = account.ServiceImportShadowed("orders.create.new");

        result.ShouldBeTrue();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void ServiceImportShadowed_NoMatch_ReturnsFalse()
    {
        // Local subscription "users.*" does NOT shadow import on "orders.create"
        var account = CreateAccount("A");
        account.SubList.Insert(MakeSub("users.*"));

        var result = account.ServiceImportShadowed("orders.create");

        result.ShouldBeFalse();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void GetShadowedServiceImports_ReturnsOnlyShadowed()
    {
        var account = CreateAccount("A");

        // Register two service imports
        RegisterServiceImport(account, "orders.create");
        RegisterServiceImport(account, "users.profile");

        // Only add a local sub that shadows "orders.create"
        account.SubList.Insert(MakeSub("orders.create"));

        var shadowed = account.GetShadowedServiceImports();

        shadowed.Count.ShouldBe(1);
        shadowed.ShouldContain("orders.create");
        shadowed.ShouldNotContain("users.profile");
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void HasShadowedImports_True_WhenShadowed()
    {
        var account = CreateAccount("A");

        RegisterServiceImport(account, "orders.create");
        account.SubList.Insert(MakeSub("orders.create"));

        account.HasShadowedImports.ShouldBeTrue();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void HasShadowedImports_False_WhenNone()
    {
        var account = CreateAccount("A");

        RegisterServiceImport(account, "orders.create");
        // No local subs — nothing shadows the import

        account.HasShadowedImports.ShouldBeFalse();
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void CheckServiceImportShadowing_ReturnsShadowingSubscriptions()
    {
        var account = CreateAccount("A");
        account.SubList.Insert(MakeSub("orders.*"));
        account.SubList.Insert(MakeSub("orders.>"));

        var result = account.CheckServiceImportShadowing("orders.create");

        result.IsShadowed.ShouldBeTrue();
        result.ImportSubject.ShouldBe("orders.create");
        result.ShadowingSubscriptions.Count.ShouldBeGreaterThan(0);
        // Both wildcard subs match "orders.create"
        result.ShadowingSubscriptions.ShouldContain("orders.*");
        result.ShadowingSubscriptions.ShouldContain("orders.>");
    }

    // Go reference: accounts.go serviceImportShadowed (~line 2015).
    [Fact]
    public void CheckServiceImportShadowing_NotShadowed()
    {
        var account = CreateAccount("A");
        account.SubList.Insert(MakeSub("users.*"));

        var result = account.CheckServiceImportShadowing("orders.create");

        result.IsShadowed.ShouldBeFalse();
        result.ImportSubject.ShouldBe("orders.create");
        result.ShadowingSubscriptions.Count.ShouldBe(0);
    }
}
