using adas_core.Application.Services.Caching;

namespace adas_core.Test.Services;

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

    /// <summary>
    /// Initializes a fresh <see cref="NoCacheService"/> instance and assigns it to <c>_noCacheService</c>
    /// to provide a clean, dependency-free test fixture prior to executing each test.
    /// </summary>
    [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

    /// <summary>
    /// Verifies that the no-cache service implementation never persists data to any backend when <c>GetOrSetObjectAsync</c> is invoked, and confirms that a subsequent <c>DeleteObjectAsync</c> on the same key does not throw.
    /// </summary>
    [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

    /// <summary>
    /// Verifies that the no-cache service's <c>DeleteByPatternAsync</c> returns 0 and does not throw when invoked with arbitrary patterns, confirming the no-op delete behavior for any key pattern.
    /// </summary>
    [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

    /// <summary>
    /// Verifies that calling CleanCache on the no-cache service is a safe no-op that does not throw,
    /// and that subsequent calls to GetValue consistently return <c>null</c> for any key.
    /// </summary>
    [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);
        }


    /// <summary>
    /// Verifies that calling <c>SetValue</c> on the no-cache service is a no-op and does not throw any exception.
    /// </summary>
    [Test]
        public void SetValue_IsNoOp_DoesNotThrow()
        {
    
            Action act = () => _noCacheService.SetValue("key", "value");
            Assert.That(act, Throws.Nothing);
    
        }


    /// <summary>
    /// Verifies that the no-cache service's GetValue method returns null for any key,
    /// confirming that the no-op implementation does not return or simulate cached values.
    /// </summary>
    [Test]
        public void GetValue_IsNoOp_ReturnsNull()
        {
            var result = _noCacheService.GetValue("any-key");
    
            Assert.That(result, Is.Null);
        }

    #endregion
}
