using adas_core.Application.Services.Caching;

namespace adas_core.Test.Services;

[TestFixture]
public class NoCacheServiceTest
{
    private NoCacheService _noCacheService = null!;

    [SetUp]
    public void SetUp()
    {
        _noCacheService = new NoCacheService();
    }

    #region TC-27

    [Test]
    public async Task GetOrSetObjectAsync_AlwaysCallsFactory_NeverUsesCache()
    {
        // Arrange
        var callCount = 0;
        var expectedResult = new { Name = "TestPatient", Id = "123" };

        Func<Task<object>> factory = () =>
        {
            callCount++;
            return Task.FromResult<object>(expectedResult);
        };

        var key = "patients:abc123";
        var ttl = TimeSpan.FromMinutes(5);

        // Act
        var result1 = await _noCacheService.GetOrSetObjectAsync(key, factory, ttl);
        var result2 = await _noCacheService.GetOrSetObjectAsync(key, factory, ttl);

        // Assert
        Assert.That(callCount, Is.EqualTo(2), "La factory debería llamarse siempre (no hay caché)");
        Assert.That(result1, Is.EqualTo(expectedResult));
        Assert.That(result2, Is.EqualTo(expectedResult));
    }

    [Test]
    public async Task GetOrSetObjectAsync_CallsFactory_ForEachUniqueKey()
    {
        // Arrange
        var callCount = 0;

        Func<Task<string>> factory = () =>
        {
            callCount++;
            return Task.FromResult($"result-{callCount}");
        };

        // Act
        await _noCacheService.GetOrSetValueAsync("key1", factory);
        await _noCacheService.GetOrSetValueAsync("key2", factory);
        await _noCacheService.GetOrSetValueAsync("key3", factory);

        // Assert
        Assert.That(callCount, Is.EqualTo(3),
            "La factory debería haber sido invocada 3 veces, una por cada clave única");
    }

    #endregion

    #region TC-28

    [Test]
    public async Task GetOrSetObjectAsync_DoesNotStoreData_InAnyBackend()
    {
        var key = "patients:abc123";
        var expectedResult = new { Name = "TestPatient" };

        Func<Task<object>> factory = () => Task.FromResult<object>(expectedResult);

        await _noCacheService.GetOrSetObjectAsync(key, factory);

        var retrieved = await _noCacheService.GetObjectAsync<object>(key);
        Assert.That(retrieved, Is.Null);


        Func<Task> act = async () => await _noCacheService.DeleteObjectAsync(key);
        Assert.That(act, Throws.Nothing);

    }


    #endregion

    #region TC-29

    [Test]
    public async Task DeleteByPatternAsync_ReturnsZero_DoesNotThrow()
    {
        // Act
        var result = await _noCacheService.DeleteByPatternAsync("patients:*");
        var result2 = await _noCacheService.DeleteByPatternAsync("any:pattern:*");

        // Assert
        Assert.That(result, Is.EqualTo(0));
        Assert.That(result2, Is.EqualTo(0));
    }

    #endregion

    #region TC-30

    [Test]
    public void CleanCache_IsNoOp_DoesNotThrow()
    {

        Action act = () => _noCacheService.CleanCache();
        Assert.That(act, Throws.Nothing);

        var result = _noCacheService.GetValue("any-key");
        Assert.That(result, Is.Null);
    }


    [Test]
    public void SetValue_IsNoOp_DoesNotThrow()
    {

        Action act = () => _noCacheService.SetValue("key", "value");
        Assert.That(act, Throws.Nothing);

    }


    [Test]
    public void GetValue_IsNoOp_ReturnsNull()
    {
        var result = _noCacheService.GetValue("any-key");

        Assert.That(result, Is.Null);
    }

    #endregion
}
