using FluentAssertions;
using WebClientTpos.Client.Services;
using Xunit;

namespace WebClientTpos.ComponentTests.Services;

/// <summary>
/// EN: Unit tests for AuthStateService — singleton tracking auth state in the POS app.
///     Token is managed by BFF httpOnly cookie; this service only tracks email, role, expiry.
/// VI: Unit tests cho AuthStateService — singleton theo dõi trạng thái auth trong POS app.
///     Token được quản lý bởi BFF httpOnly cookie; service này chỉ lưu email, role, expiry.
/// </summary>
public class AuthStateServiceTests
{
    private static AuthStateService CreateSut() => new();

    // -----------------------------------------------------------------------
    // Initial state
    // -----------------------------------------------------------------------

    [Fact]
    public void InitialState_ShouldNotBeAuthenticated()
    {
        // Arrange & Act
        var sut = CreateSut();

        // Assert
        sut.IsAuthenticated.Should().BeFalse();
        sut.UserEmail.Should().BeNull();
        sut.UserRole.Should().BeNull();
        sut.TokenExpiry.Should().BeNull();
    }

    // -----------------------------------------------------------------------
    // Login
    // -----------------------------------------------------------------------

    [Fact]
    public void Login_WithValidCredentials_ShouldSetAuthenticatedState()
    {
        // Arrange
        var sut = CreateSut();

        // Act
        sut.Login("owner@goodgo.vn", "owner");

        // Assert
        sut.IsAuthenticated.Should().BeTrue();
        sut.UserEmail.Should().Be("owner@goodgo.vn");
        sut.UserRole.Should().Be("owner");
    }

    [Theory]
    [InlineData("owner")]
    [InlineData("staff")]
    [InlineData("customer")]
    [InlineData("branch")]
    public void Login_WithAnyRole_ShouldSetRole(string role)
    {
        // Arrange
        var sut = CreateSut();

        // Act
        sut.Login("user@goodgo.vn", role);

        // Assert
        sut.UserRole.Should().Be(role);
    }

    [Fact]
    public void Login_CalledTwiceWithSameData_ShouldNotFireOnChange()
    {
        // Arrange
        var sut = CreateSut();
        sut.Login("user@goodgo.vn", "owner");
        var changeCount = 0;
        sut.OnChange += () => changeCount++;

        // Act — same email + same role again
        sut.Login("user@goodgo.vn", "owner");

        // Assert
        // EN: Idempotent login must not trigger OnChange / VI: Login idempotent không kích hoạt OnChange
        changeCount.Should().Be(0);
    }

    [Fact]
    public void Login_WithNewRole_ShouldFireOnChange()
    {
        // Arrange
        var sut = CreateSut();
        sut.Login("user@goodgo.vn", "staff");
        var changeCount = 0;
        sut.OnChange += () => changeCount++;

        // Act
        sut.Login("user@goodgo.vn", "owner");

        // Assert
        changeCount.Should().BeGreaterThan(0);
    }

    // -----------------------------------------------------------------------
    // Logout
    // -----------------------------------------------------------------------

    [Fact]
    public void Logout_AfterLogin_ShouldClearState()
    {
        // Arrange
        var sut = CreateSut();
        sut.Login("owner@goodgo.vn", "owner");

        // Act
        sut.Logout();

        // Assert
        sut.IsAuthenticated.Should().BeFalse();
        sut.UserEmail.Should().BeNull();
        sut.UserRole.Should().BeNull();
    }

    [Fact]
    public void Logout_ShouldFireOnChange()
    {
        // Arrange
        var sut = CreateSut();
        sut.Login("user@goodgo.vn", "staff");
        var fired = false;
        sut.OnChange += () => fired = true;

        // Act
        sut.Logout();

        // Assert
        fired.Should().BeTrue();
    }

    // -----------------------------------------------------------------------
    // GetPortalUrl
    // -----------------------------------------------------------------------

    [Theory]
    [InlineData("owner", "/admin")]
    [InlineData("admin", "/admin")]
    [InlineData("staff", "/staff/dashboard")]
    [InlineData("branch", "/admin")]
    [InlineData("customer", "/app")]
    [InlineData("unknown", "/auth/login")]
    [InlineData(null, "/auth/login")]
    public void GetPortalUrl_ShouldReturnCorrectPathForRole(string? role, string expectedUrl)
    {
        // Arrange
        var sut = CreateSut();
        if (role != null)
        {
            sut.Login("user@goodgo.vn", role);
        }

        // Act
        var url = sut.GetPortalUrl();

        // Assert
        url.Should().Be(expectedUrl);
    }

    // -----------------------------------------------------------------------
    // OnChange event
    // -----------------------------------------------------------------------

    [Fact]
    public void OnChange_ShouldBeRaisedOnLogin()
    {
        // Arrange
        var sut = CreateSut();
        var raised = false;
        sut.OnChange += () => raised = true;

        // Act
        sut.Login("new@goodgo.vn", "owner");

        // Assert
        raised.Should().BeTrue();
    }

    [Fact]
    public void OnChange_MultipleSubscribers_ShouldAllBeNotified()
    {
        // Arrange
        var sut = CreateSut();
        var count = 0;
        sut.OnChange += () => count++;
        sut.OnChange += () => count++;
        sut.OnChange += () => count++;

        // Act
        sut.Logout();

        // Assert
        count.Should().Be(3);
    }
}
