using Xunit;
using CacheModule;
using Newtonsoft.Json;

namespace CacheModuleTest{
    public class CacheServiceIntegratedTest
    {
        private class MockIntegration{
            private CacheService _cacheService;
            public Dictionary<string, List<int>> keyValuePairs = new Dictionary<string, List<int>>(){
                {"first", new List<int>(){1,2,3}},
                {"second", new List<int>(){4,5,6}},
                {"third", new List<int>(){7,8,9}}
            }; 
            public MockIntegration(){
                _cacheService = CacheService.Instance;
            }

            public int Get(string key, int index){
                return keyValuePairs[key][index];
            }
            public int GetSum(string key){
                return keyValuePairs[key].Sum();
            }

            public int CachedGet(string key, int index){
                var json = JsonConvert.SerializeObject(new List<object>(){key, index}) ?? string.Empty;
                var cachedObject = _cacheService.Get(nameof(Get), json);
                if(cachedObject != null){
                    return (int)cachedObject;
                }
                var result = Get(key, index);
                _cacheService.Add(nameof(Get), json, result, Duration.OneMinute);
                return result;
            }

            public int CachedGetSum(string key){
                var json = JsonConvert.SerializeObject(new List<object>(){key}) ?? string.Empty;
                var cachedObject = _cacheService.Get(nameof(GetSum), json);
                if(cachedObject != null){
                    return (int)cachedObject;
                }
                var result = GetSum(key);
                _cacheService.Add(nameof(GetSum), json, result, Duration.OneMinute);
                return result;
            }

            public void Clear(){
                _cacheService.Clear();
            }
        }

        [Fact]
        public void CachedGet_WhenCalledWithinDuration_ReturnsCachedValue()
        {
            // Arrange
            var mockIntegration = new MockIntegration();
            mockIntegration.Clear();
            var key = "first";
            var index = 1;
            var expected = mockIntegration.Get(key, index);
            var cachedExpected = mockIntegration.CachedGet(key, index);
            mockIntegration.keyValuePairs[key][index] = 100;

            // Act
            var cachedResult = mockIntegration.CachedGet(key, index);

            // Assert
            Assert.Equal(expected, cachedResult);
            Assert.Equal(cachedExpected, cachedResult);
        }

        [Fact]
        public void CachedGet_WhenCalledAfterDuration_ReturnsNewValue()
        {
            // Arrange
            var mockIntegration = new MockIntegration();
            mockIntegration.Clear();
            var key = "first";
            var index = 1;
            var expected = mockIntegration.Get(key, index);
            var cachedExpected = mockIntegration.CachedGet(key, index);
            mockIntegration.keyValuePairs[key][index] = 100;

            // Act
            System.Threading.Thread.Sleep(61000);
            var cachedResult = mockIntegration.CachedGet(key, index);

            // Assert
            Assert.Equal(100, cachedResult);
            Assert.NotEqual(cachedExpected, cachedResult);
        }

        [Fact]
        public void CachedGetSum_WhenCalledWithinDuration_ReturnsCachedValue()
        {
            // Arrange
            var mockIntegration = new MockIntegration();
            mockIntegration.Clear();
            var key = "first";
            var expected = mockIntegration.GetSum(key);
            var cachedExpected = mockIntegration.CachedGetSum(key);
            mockIntegration.keyValuePairs[key] = new List<int>(){100, 100, 100};

            // Act
            var cachedResult = mockIntegration.CachedGetSum(key);

            // Assert
            Assert.Equal(expected, cachedResult);
            Assert.Equal(cachedExpected, cachedResult);
        }

        [Fact]
        public void CachedGetSum_WhenCalledAfterDuration_ReturnsNewValue()
        {
            // Arrange
            var mockIntegration = new MockIntegration();
            mockIntegration.Clear();
            var key = "first";
            var expected = mockIntegration.GetSum(key);
            var cachedExpected = mockIntegration.CachedGetSum(key);
            mockIntegration.keyValuePairs[key] = new List<int>(){100, 100, 100};

            // Act
            System.Threading.Thread.Sleep(61000);
            var cachedResult = mockIntegration.CachedGetSum(key);

            // Assert
            Assert.Equal(300, cachedResult);
            Assert.NotEqual(cachedExpected, cachedResult);
        }
    }
}

