using EntKube.Provisioning.Domain;
using FluentAssertions;

namespace EntKube.Provisioning.Tests.Domain;

public class ServiceInstanceTests
{
    [Fact]
    public void Provision_WithValidInputs_CreatesInstanceInPendingState()
    {
        // Arrange & Act — Request provisioning of a MinIO instance.

        Guid clusterId = Guid.NewGuid();

        ServiceInstance instance = ServiceInstance.Provision(
            clusterId,
            ServiceType.MinIO,
            "tenant-storage",
            "minio-system");

        // Assert — Starts pending until the reconciler deploys it.

        instance.Id.Should().NotBe(Guid.Empty);
        instance.ClusterId.Should().Be(clusterId);
        instance.ServiceType.Should().Be(ServiceType.MinIO);
        instance.Name.Should().Be("tenant-storage");
        instance.Namespace.Should().Be("minio-system");
        instance.DesiredState.Should().Be(ServiceState.Running);
        instance.CurrentState.Should().Be(ServiceState.Pending);
    }

    [Fact]
    public void Provision_WithEmptyName_ThrowsArgumentException()
    {
        // Arrange & Act

        Action act = () => ServiceInstance.Provision(Guid.NewGuid(), ServiceType.MinIO, "", "ns");

        // Assert

        act.Should().Throw<ArgumentException>()
            .WithParameterName("name");
    }

    [Fact]
    public void MarkRunning_UpdatesCurrentState()
    {
        // Arrange

        ServiceInstance instance = ServiceInstance.Provision(Guid.NewGuid(), ServiceType.CloudNativePG, "db", "cnpg-system");

        // Act

        instance.MarkRunning();

        // Assert

        instance.CurrentState.Should().Be(ServiceState.Running);
        instance.LastReconcileAt.Should().NotBeNull();
    }

    [Fact]
    public void RequestDecommission_SetsDesiredStateToDecommissioned()
    {
        // Arrange

        ServiceInstance instance = ServiceInstance.Provision(Guid.NewGuid(), ServiceType.Keycloak, "auth", "keycloak-system");
        instance.MarkRunning();

        // Act — Tenant admin decides to tear down this service.

        instance.RequestDecommission();

        // Assert — Desired state changes but current state remains until reconciler acts.

        instance.DesiredState.Should().Be(ServiceState.Decommissioned);
        instance.CurrentState.Should().Be(ServiceState.Running);
    }
}
